{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "We demonstrate an application of an interact." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The Chebyshev Four Bar Mechanism" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Chebyshev mechanism translates circular motion into linear motion, and vice versa." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. The Crank" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will make a interactive web page to model a four bar mechanism.\n", "The mechanism is attributed to Chebyshev and transmits straight to circular motion.\n", "Let us first start with the making of an interact for a crank." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Widget Javascript not detected. It may not be installed or enabled properly. Reconnecting the current kernel may help.\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "4580711b7bab47808bb1f92d998c3f0f" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "@interact\n", "def show_crank(angle = slider(0, 2*pi, pi/20, pi/10, label='angle')):\n", " \"\"\"\n", " Shows the drawing of a crank, where the user can slide the angle\n", " to turn the crank.\n", " \"\"\"\n", " center = (0,0)\n", " endpnt = (cos(angle), sin(angle))\n", " pltcnt = point(center, size=50)\n", " pltend = point(endpnt, size=50)\n", " crank = line([center, endpnt])\n", " (pltcnt+crank+pltend).show(xmin=-1, xmax=1, ymin=-1, ymax=+1, figsize=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the `aspect_ratio = 1` is missing. But it is good enough as a start." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. The Connector Coordinates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a bar connected to the end point of the crank.\n", "The end point of that bar is connected to another bar, of length 5/2,\n", "that originates at (2,0).\n", "To find the coordinates of the connector point, we intersect two circles." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x^2 - 2*x*c + y^2 - 2*y*s + c^2 + s^2 - 25/4, x^2 - 4*x + y^2 - 9/4)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PR. = PolynomialRing(QQ, order='lex')\n", "p = (x-c)^2 + (y-s)^2 - (5/2)^2\n", "q = (x-2)^2 + y^2 - (5/2)^2\n", "(p, q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the resultant we get symbolic values for the coordinates,\n", "in function of the end point coordinates (c, s) of the crank." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4*y^2*c^2 - 16*y^2*c + 4*y^2*s^2 + 16*y^2 - 4*y*c^2*s + 16*y*c*s - 4*y*s^3 - 16*y*s + c^4 - 8*c^3 + 2*c^2*s^2 - c^2 - 8*c*s^2 + 68*c + s^4 + 8*s^2 - 84" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ry = p.resultant(q,x)\n", "ry" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4*x^2*c^2 - 16*x^2*c + 4*x^2*s^2 + 16*x^2 - 4*x*c^3 + 8*x*c^2 - 4*x*c*s^2 + 16*x*c - 8*x*s^2 - 32*x + c^4 + 2*c^2*s^2 - 8*c^2 + s^4 - 17*s^2 + 16" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rx = p.resultant(q,y)\n", "rx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To solve the polynomials for x and y, we must convert back to the Symbolic Ring (SR)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[x == 1/2*(c^3 + (c + 2)*s^2 - 2*c^2 - sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*s - 4*c + 8)/(c^2 + s^2 - 4*c + 4), x == 1/2*(c^3 + (c + 2)*s^2 - 2*c^2 + sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*s - 4*c + 8)/(c^2 + s^2 - 4*c + 4)]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x, y, c, s = var('x,y,c,s')\n", "sx = solve(SR(rx),x)\n", "sx" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[y == 1/2*(s^3 + (c^2 - 4*c + 4)*s - sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*(c - 2))/(c^2 + s^2 - 4*c + 4), y == 1/2*(s^3 + (c^2 - 4*c + 4)*s + sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*(c - 2))/(c^2 + s^2 - 4*c + 4)]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sy = solve(SR(ry),y)\n", "sy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We take the second solution as coordinates for x \n", "and the first solution for the coordinates for y." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1/2*(c^3 + (c + 2)*s^2 - 2*c^2 + sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*s - 4*c + 8)/(c^2 + s^2 - 4*c + 4)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xv = sx[1].rhs()\n", "xv" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1/2*(s^3 + (c^2 - 4*c + 4)*s - sqrt(-c^4 - s^4 + 8*c^3 - (2*c^2 - 8*c - 17)*s^2 + c^2 - 68*c + 84)*(c - 2))/(c^2 + s^2 - 4*c + 4)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "yv = sy[0].rhs()\n", "yv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Crank and Connector" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have the symbolic coordinates of the connector, we can extend the interact for the crank showing the connector." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Widget Javascript not detected. It may not be installed or enabled properly. Reconnecting the current kernel may help.\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d432ad7ac96b414890263f915a1f617e" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fx(cs, sn) = xv.subs(c=cs, s=sn)\n", "fy(cs, sn) = yv.subs(c=cs, s=sn)\n", "@interact\n", "def connector(angle = slider(0, 2*pi, pi/20, 7*pi/20, label='angle')):\n", " \"\"\"\n", " Shows the drawing of a crank, where the user can slide the angle\n", " to turn the crank. Also the connector point is drawn.\n", " \"\"\"\n", " center = (0,0)\n", " c = cos(angle)\n", " s = sin(angle)\n", " endpnt = (c, s)\n", " (x, y) = (fx(c,s), fy(c,s))\n", " pltcnt = point(center, size=50)\n", " pltend = point(endpnt, size=50)\n", " connector = point((x,y), size=50)\n", " crank = line([center, endpnt])\n", " bartwobase = point((2,0),size=50)\n", " bartwo = line([(2,0), (x,y)], color='red')\n", " barthree = line([endpnt, (x,y)], color='green')\n", " bars = crank + bartwo + barthree\n", " pnts = pltcnt + connector + pltend + bartwobase\n", " plt = bars + pnts \n", " plt.show(xmin=-1, xmax=3, ymin=-1, ymax=+3, figsize=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. The Coupler" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The final addition is the coupler point and the fourth bar." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Widget Javascript not detected. It may not be installed or enabled properly. Reconnecting the current kernel may help.\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "0c391cef4d2e4be8ae3d1144c7dd22ff" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "@interact\n", "def coupler(angle = slider(0, 2*pi, pi/20, 7*pi/20, label='angle')):\n", " \"\"\"\n", " Shows the drawing of a crank, where the user can slide the angle\n", " to turn the crank. Also the connector point is drawn,\n", " with the coupler point and fourth bar.\n", " \"\"\"\n", " center = (0,0)\n", " c = cos(angle)\n", " s = sin(angle)\n", " endpnt = (c, s)\n", " (x, y) = (fx(c,s), fy(c,s))\n", " dx = x - c\n", " dy = y - s\n", " xx = x + dx\n", " yy = y + dy\n", " pltcnt = point(center, size=50)\n", " pltend = point(endpnt, size=50)\n", " connector = point((x,y), size=50)\n", " coupler = point((xx,yy), size=50, color='red')\n", " crank = line([center, endpnt])\n", " bartwobase = point((2,0),size=50)\n", " bartwo = line([(2,0), (x,y)], color='red')\n", " barthree = line([endpnt, (x,y)], color='green')\n", " barfour = line([(x,y), (xx,yy)], color='blue')\n", " bars = crank + bartwo + barthree + barfour\n", " pnts = pltcnt + connector + pltend + bartwobase + coupler\n", " plt = bars + pnts \n", " plt.show(xmin=-1, xmax=5, ymin=-1, ymax=+5, figsize=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. Extensions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Several extensions will make this interact even more interesting, below are two suggestions:\n", "\n", "1. Draw *the coupler curve*, this is the curve traced by the coupler point.\n", "\n", "2. Add addition sliders to control the parameters of the mechanism, one slider to control the length of each bar." ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 10.3", "language": "sage", "name": "sagemath" }, "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.10.6" } }, "nbformat": 4, "nbformat_minor": 2 }