{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Velocity and Acceleration of a point of a rigid body\n", "\n", "> Renato Naville Watanabe, Marcos Duarte \n", "> [Laboratory of Biomechanics and Motor Control](http://pesquisa.ufabc.edu.br/bmclab) \n", "> Federal University of ABC, Brazil" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "This notebook shows the expressions of the velocity and acceleration of a point on rigid body, given the angular velocity of the body." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Python setup" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib notebook\n", "from matplotlib.animation import FuncAnimation\n", "from matplotlib.patches import FancyArrowPatch" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Frame of reference attached to a body\n", "\n", "The concept of reference frame in Biomechanics and motor control is very important and central to the understanding of human motion. For example, do we see, plan and control the movement of our hand with respect to reference frames within our body or in the environment we move? Or a combination of both? \n", "The figure below, although derived for a robotic system, illustrates well the concept that we might have to deal with multiple coordinate systems. \n", "\n", "
Figure. Multiple coordinate systems for use in robots (figure from Corke (2017)).
\n", "\n", "For three-dimensional motion analysis in Biomechanics, we may use several different references frames for convenience and refer to them as global, laboratory, local, anatomical, or technical reference frames or coordinate systems (we will study this later). \n", "There has been proposed different standardizations on how to define frame of references for the main segments and joints of the human body. For instance, the International Society of Biomechanics has a [page listing standardization proposals](https://isbweb.org/activities/standards) by its standardization committee and subcommittees:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Position of a point on a rigid body\n", "\n", "The description of the position of a point P of a rotating rigid body is given by:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{r}_{P/O}} = x_{P/O}^*{\\bf\\hat{i}'} + y_{P/O}^*{\\bf\\hat{j}'}\n", "\\end{equation}\n", "\n", "\n", "where $x_{P/O}^*$ and $y_{P/O}^*$ are the coordinates of the point P position at a reference state with the versors described as:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{i}'} = \\cos(\\theta){\\bf\\hat{i}}+\\sin(\\theta){\\bf\\hat{j}}\n", "\\end{equation}\n", "\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{j}'} = -\\sin(\\theta){\\bf\\hat{i}}+\\cos(\\theta){\\bf\\hat{j}}\n", "\\end{equation}\n", "\n", "\n", "\n", "\n", "\n", "Note that the vector ${\\bf\\vec{r}_{P/O}}$ has always the same description for any point P of the rigid body when described as a linear combination of ${\\bf\\hat{i}'}$ and ${\\bf\\hat{j}'}$.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Translation of a rigid body\n", "\n", " Let's consider now the case in which, besides a rotation, a translation of the body happens. This situation is represented in the figure below. In this case, the position of the point P is given by:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{r}_{P/O}} = {\\bf\\vec{r}_{A/O}}+{\\bf\\vec{r}_{P/A}}= {\\bf\\vec{r}_{A/O}}+x_{P/A}^*{\\bf\\hat{i}'} + y_{P/A}^*{\\bf\\hat{j}'}\n", "\\end{equation}\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Angular velocity of a body\n", "\n", "The magnitude of the angular velocity of a rigid body rotating on a plane is defined as:\n", "\n", "\n", "\\begin{equation}\n", " \\omega = \\frac{d\\theta}{dt}\n", "\\end{equation}\n", "\n", "\n", "Usually, it is defined an angular velocity vector perpendicular to the plane where the rotation occurs (in this case the x-y plane) and with magnitude $\\omega$:\n", "\n", "\n", "\\begin{equation}\n", " \\vec{\\bf{\\omega}} = \\omega\\hat{\\bf{k}}\n", "\\end{equation}\n", "\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Velocity of a point with no translation" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "First we will consider the situation with no translation. The velocity of the point P is given by:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}_{P/O}} = \\frac{d{\\bf\\vec{r}_{P/O}}}{dt} = \\frac{d(x_{P/O}^*{\\bf\\hat{i}'} + y_{P/O}^*{\\bf\\hat{j}'})}{dt}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "To continue this deduction, we have to find the expression of the derivatives of \n", "${\\bf\\hat{i}'}$ and ${\\bf\\hat{j}'}$. This is very similar to the derivative expressions of ${\\bf\\hat{e_R}}$ and ${\\bf\\hat{e_\\theta}}$ of [polar basis](http://nbviewer.jupyter.org/github/BMClab/bmc/blob/master/notebooks/PolarBasis.ipynb).\n", "\n", "\n", "\\begin{equation}\n", "\\frac{d{\\bf\\hat{i}'}}{dt} = -\\dot{\\theta}\\sin(\\theta){\\bf\\hat{i}}+\\dot{\\theta}\\cos(\\theta){\\bf\\hat{j}} = \\dot{\\theta}{\\bf\\hat{j}'}\n", "\\end{equation}\n", "\n", "\n", "\n", "\\begin{equation}\n", "\\frac{d{\\bf\\hat{j}'}}{dt} = -\\dot{\\theta}\\cos(\\theta){\\bf\\hat{i}}-\\dot{\\theta}\\sin(\\theta){\\bf\\hat{j}} = -\\dot{\\theta}{\\bf\\hat{i}'}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "Another way to represent the expressions above is by using the vector form to express the angular velocity $\\dot{\\theta}$. It is usual to represent the angular velocity as a vector in the direction ${\\bf\\hat{k}}$: ${\\bf\\vec{\\omega}} = \\dot{\\theta}{\\bf\\hat{k}} = \\omega{\\bf\\hat{k}}$. Using this definition of the angular velocity, we can write the above expressions as:\n", "\n", "\n", "\\begin{equation}\n", "\\frac{d{\\bf\\hat{i}'}}{dt} = \\dot{\\theta}{\\bf\\hat{j}'} = \\dot{\\theta} {\\bf\\hat{k}}\\times {\\bf\\hat{i}'} = {\\bf\\vec{\\omega}} \\times {\\bf\\hat{i}'}\n", "\\end{equation}\n", "\n", "\n", "\n", "\\begin{equation}\n", "\\frac{d{\\bf\\hat{j}'}}{dt} = -\\dot{\\theta}{\\bf\\hat{i}'} = \\dot{\\theta} {\\bf\\hat{k}}\\times {\\bf\\hat{j}'} ={\\bf\\vec{\\omega}} \\times {\\bf\\hat{j}'}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "So, the velocity of the point P in the situation of no translation is:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}_{P/O}} = \\frac{d(x_{P/O}^*{\\bf\\hat{i}'} + y_{P/O}^*{\\bf\\hat{j}'})}{dt} = x_{P/O}^*\\frac{d{\\bf\\hat{i}'}}{dt} + y_{P/O}^*\\frac{d{\\bf\\hat{j}'}}{dt}=x_{P/O}^*{\\bf\\vec{\\omega}} \\times {\\bf\\hat{i}'} + y_{P/O}^*{\\bf\\vec{\\omega}} \\times {\\bf\\hat{j}'} = {\\bf\\vec{\\omega}} \\times \\left(x_{P/O}^*{\\bf\\hat{i}'}\\right) + {\\bf\\vec{\\omega}} \\times \\left(y_{P/O}^*{\\bf\\hat{j}'}\\right) ={\\bf\\vec{\\omega}} \\times \\left(x_{P/O}^*{\\bf\\hat{i}'}+y_{P/O}^*{\\bf\\hat{j}'}\\right)\n", "\\end{equation}\n", "\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}_{P/O}} = {\\bf\\vec{\\omega}} \\times {\\bf{\\vec{r}_{P/O}}}\n", "\\end{equation}\n", "\n", "\n", "This expression shows that the velocity vector of any point of a rigid body is orthogonal to the vector linking the point O and the point P.\n", "\n", "It is worth to note that despite the above expression was deduced for a planar movement, the expression above is general, including three dimensional movements." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Relative velocity of a point on a rigid body to another point\n", "\n", "To compute the velocity of a point on a rigid body that is translating, we need to find the expression of the velocity of a point (P) in relation to another point on the body (A). So:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}_{P/A}} = {\\bf\\vec{v}_{P/O}}-{\\bf\\vec{v}_{A/O}} = {\\bf\\vec{\\omega}} \\times {\\bf{\\vec{r}_{P/O}}} - {\\bf\\vec{\\omega}} \\times {\\bf{\\vec{r}_{A/O}}} = {\\bf\\vec{\\omega}} \\times ({\\bf{\\vec{r}_{P/O}}}-{\\bf{\\vec{r}_{A/O}}}) = {\\bf\\vec{\\omega}} \\times {\\bf{\\vec{r}_{P/A}}}\n", "\\end{equation}\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Velocity of a point on rigid body translating\n", "\n", "The velocity of a point on a rigid body that is translating is given by:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}_{P/O}} = \\frac{d{\\bf\\vec{r}_{P/O}}}{dt} = \\frac{d({\\bf\\vec{r}_{A/O}}+x_{P/A}^*{\\bf\\hat{i}'} + y_{P/A}^*{\\bf\\hat{j}'})}{dt} = \\frac{d{\\bf\\vec{r}_{A/O}}}{dt}+\\frac{d(x_{P/A}^*{\\bf\\hat{i}'} + y_{P/A}^*{\\bf\\hat{j}'})}{dt} = {\\bf\\vec{v}_{A/O}} + {\\bf\\vec{\\omega}} \\times {\\bf{\\vec{r}_{P/A}}}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Below is an example of a body rotating with the angular velocity of $\\omega = \\pi/10$ rad/s and translating at the velocity of \n", "${\\bf\\vec{v}} = 0.7 {\\bf\\hat{i}} + 0.5 {\\bf\\hat{j}}$ m/s. The red arrow indicates the velocity of the geometric center of the body and the blue arrow indicates the velocity of the lower point of the body" ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
');\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('
');\n", " var button = $('');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = np.linspace(0, 20, 40)\n", "\n", "alpha = np.pi/150 #[rad/s^2] angular acceleration \n", "\n", "omega0 = np.pi/100 #[rad/s] angular velocity\n", "\n", "aoa = np.array([[0.01],[0.05]]) # linear acceleration\n", "\n", "fig = plt.figure()\n", "plt.grid()\n", "ax = fig.add_axes([0, 0, 1, 1]) \n", "ax.axis(\"on\")\n", "plt.rcParams['figure.figsize']=5,5\n", "theta = 0\n", "omega = 0\n", "def run(i):\n", " ax.clear()\n", " phi = np.linspace(0,2*np.pi,100)\n", " B = np.squeeze(np.array([[2*np.cos(phi)],[6*np.sin(phi)]]))\n", " Baum = np.vstack((B,np.ones((1,np.shape(B)[1]))))\n", " \n", " omega = alpha*t[i]+omega0 #[rad/s] angular velocity\n", " \n", " theta = alpha/2*t[i]**2 + omega0*t[i] # [rad] angle\n", " \n", " voa = aoa*t[i] # linear velocity\n", " \n", " roa = aoa/2*t[i]**2 # position of the center of the body\n", " \n", " R = np.array([[np.cos(theta), -np.sin(theta)],[np.sin(theta), np.cos(theta)]])\n", " T = np.vstack((np.hstack((R,roa)), np.array([0,0,1])))\n", " BRot = R@B\n", " BRotTr = T@Baum \n", " \n", " plt.plot(BRotTr[0,:],BRotTr[1,:], roa[0], roa[1],'.')\n", " plt.fill(BRotTr[0,:],BRotTr[1,:],'g')\n", " \n", " element = 75\n", " \n", " ap = (aoa + np.cross(np.array([0,0,alpha]), BRot[:,[element]].T)[:,0:2].T \n", " - omega**2*BRot[:,[element]])\n", " \n", " vVP = FancyArrowPatch(BRotTr[0:2,element], BRotTr[0:2,element] + 5*ap.squeeze(),\n", " mutation_scale=20, \n", " lw=2, arrowstyle=\"->\", color=\"b\", alpha=1)\n", " ax.add_artist(vVP)\n", " \n", " plt.xlim((-10, 20))\n", " plt.ylim((-10, 20))\n", " \n", " \n", "\n", "ani = FuncAnimation(fig, run, frames=50, repeat=False, interval=500)\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Further reading\n", "\n", "- Read pages 958-971 of the 18th chapter of the [Ruina and Rudra's book] (http://ruina.tam.cornell.edu/Book/index.html) about circular motion of particle. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Video lectures on the Internet\n", "\n", "- [Kinematics Of Rigid Bodies - General Plane Motion - Solved Problems](https://www.youtube.com/watch?v=4LsLy9iJKFA)\n", "- [Kinematics of Rigid Bodies -Translation And Rotation About Fixed Axis - Rectilinear and Rotational](https://www.youtube.com/watch?v=VnzsQmP6eMQ) " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "## Problems\n", "\n", "1. Solve the problems 16.2.5, 16.2.10, 16.2.11 and 16.2.20 from [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html).\n", "2. Solve the problems 17.1.2, 17.1.8, 17.1.9, 17.1.10, 17.1.11 and 17.1.12 from [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html).\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Reference\n", "\n", "- Ruina A, Rudra P (2019) [Introduction to Statics and Dynamics](http://ruina.tam.cornell.edu/Book/index.html). Oxford University Press.\n", "- Corke P (2017) [Robotics, Vision and Control: Fundamental Algorithms in MATLAB](http://www.petercorke.com/RVC/). 2nd ed. Springer-Verlag Berlin." ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "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.7.3" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "nbTranslate": { "displayLangs": [ "*" ], "hotkey": "alt-t", "langInMainMenu": true, "sourceLang": "en", "targetLang": "pt", "useGoogleTranslate": true }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }