Created
November 7, 2016 22:22
-
-
Save bmander/37e13ff1e8c3cf7d14d968cd1c39d547 to your computer and use it in GitHub Desktop.
Deriving inverted pendulum equations of motion two different ways
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Two ways of deriving pendulum-cart system equations of motion" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 1: Lagrange's method, by hand" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"import sympy\n", | |
"from sympy import sin,cos, symbols\n", | |
"from sympy.physics.mechanics import dynamicsymbols\n", | |
"\n", | |
"from sympy.physics.vector import init_vprinting\n", | |
"init_vprinting(use_latex='mathjax', pretty_print=False)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### define useful variables" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$t$$" | |
], | |
"text/plain": [ | |
"t" | |
] | |
}, | |
"execution_count": 2, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# time\n", | |
"\n", | |
"t = sympy.Symbol(\"t\")\n", | |
"t" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left ( x, \\quad \\theta\\right )$$" | |
], | |
"text/plain": [ | |
"(x, theta)" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# generalized coordinates\n", | |
"\n", | |
"# x is cart rightward from O, theta is pendulum up, counter-clockwise\n", | |
"x, theta = dynamicsymbols('x theta')\n", | |
"x,theta" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left ( \\dot{x}, \\quad \\dot{\\theta}\\right )$$" | |
], | |
"text/plain": [ | |
"(x', theta')" | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# generalized speeds\n", | |
"\n", | |
"v,omega = dynamicsymbols('x theta',1)\n", | |
"v,omega" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left ( m, \\quad M, \\quad l, \\quad g\\right )$$" | |
], | |
"text/plain": [ | |
"(m, M, l, g)" | |
] | |
}, | |
"execution_count": 5, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# constants\n", | |
"\n", | |
"m,M,l,g = symbols(\"m M l g\")\n", | |
"m,M,l,g" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### define kinetic energy T" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"v_mx = v - cos(theta)*l*omega\n", | |
"v_my = -sin(theta)*l*omega" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$l^{2} \\operatorname{sin}^{2}\\left(\\theta\\right) \\dot{\\theta}^{2} + \\left(- l \\operatorname{cos}\\left(\\theta\\right) \\dot{\\theta} + \\dot{x}\\right)^{2}$$" | |
], | |
"text/plain": [ | |
"l**2*sin(theta)**2*theta'**2 + (-l*cos(theta)*theta' + x')**2" | |
] | |
}, | |
"execution_count": 7, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"v_m_sq = v_mx**2 + v_my**2\n", | |
"v_m_sq" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"T = sympy.Rational(1,2)*M*v**2 + sympy.Rational(1,2)*m*v_m_sq" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\frac{M \\dot{x}^{2}}{2} + \\frac{m}{2} \\left(l^{2} \\operatorname{sin}^{2}\\left(\\theta\\right) \\dot{\\theta}^{2} + \\left(- l \\operatorname{cos}\\left(\\theta\\right) \\dot{\\theta} + \\dot{x}\\right)^{2}\\right)$$" | |
], | |
"text/plain": [ | |
"M*x'**2/2 + m*(l**2*sin(theta)**2*theta'**2 + (-l*cos(theta)*theta' + x')**2)/2" | |
] | |
}, | |
"execution_count": 9, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"T" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### define potential energy V" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"V = m*g*l*sympy.cos(theta)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$g l m \\operatorname{cos}\\left(\\theta\\right)$$" | |
], | |
"text/plain": [ | |
"g*l*m*cos(theta)" | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"V" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### define lagrangian" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\frac{M \\dot{x}^{2}}{2} - g l m \\operatorname{cos}\\left(\\theta\\right) + \\frac{m}{2} \\left(l^{2} \\operatorname{sin}^{2}\\left(\\theta\\right) \\dot{\\theta}^{2} + \\left(- l \\operatorname{cos}\\left(\\theta\\right) \\dot{\\theta} + \\dot{x}\\right)^{2}\\right)$$" | |
], | |
"text/plain": [ | |
"M*x'**2/2 - g*l*m*cos(theta) + m*(l**2*sin(theta)**2*theta'**2 + (-l*cos(theta)*theta' + x')**2)/2" | |
] | |
}, | |
"execution_count": 12, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"L = T-V\n", | |
"L" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### use the Euler-Langrange equations to find equations of motion" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$l m \\operatorname{sin}\\left(\\theta\\right) \\dot{\\theta}^{2} - l m \\operatorname{cos}\\left(\\theta\\right) \\ddot{\\theta} + \\left(M + m\\right) \\ddot{x}$$" | |
], | |
"text/plain": [ | |
"l*m*sin(theta)*theta'**2 - l*m*cos(theta)*theta'' + (M + m)*x''" | |
] | |
}, | |
"execution_count": 13, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"#this equals F\n", | |
"(L.diff(v).diff(t) - L.diff(x)).expand().collect(v)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$l m \\left(- g \\operatorname{sin}\\left(\\theta\\right) + l \\ddot{\\theta} - \\operatorname{cos}\\left(\\theta\\right) \\ddot{x}\\right)$$" | |
], | |
"text/plain": [ | |
"l*m*(-g*sin(theta) + l*theta'' - cos(theta)*x'')" | |
] | |
}, | |
"execution_count": 14, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"#this equals 0\n", | |
"(L.diff(omega).diff(t) - L.diff(theta)).simplify()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Kane's Method, using Sympy API" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"from sympy import symbols, Matrix\n", | |
"from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame\n", | |
"from sympy.physics.mechanics import Point, Particle, KanesMethod\n", | |
"import numpy as np\n", | |
"\n", | |
"from sympy.physics.vector import init_vprinting\n", | |
"init_vprinting(use_latex='mathjax', pretty_print=False)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left ( \\theta, \\quad v, \\quad \\omega\\right )$$" | |
], | |
"text/plain": [ | |
"(theta, v, omega)" | |
] | |
}, | |
"execution_count": 16, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"theta, v, omega = dynamicsymbols('theta v omega')\n", | |
"theta, v, omega" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left ( m, \\quad M, \\quad l, \\quad g\\right )$$" | |
], | |
"text/plain": [ | |
"(m, M, l, g)" | |
] | |
}, | |
"execution_count": 17, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"m, M, l, g = symbols('m M l g')\n", | |
"m, M, l, g" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(P, I)" | |
] | |
}, | |
"execution_count": 18, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# inertial reference frame\n", | |
"I = ReferenceFrame('I')\n", | |
"\n", | |
"# pendulum reference frame\n", | |
"P = ReferenceFrame('P')\n", | |
"P,I" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"P.orient(I, 'Axis', (theta, I.z))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(B, C)" | |
] | |
}, | |
"execution_count": 20, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# inertial frame origin. this isn't required for finding equations of motion.\n", | |
"#O = Point('O') \n", | |
"B = Point('B') #pendulum bob\n", | |
"C = Point('C') #pendulum cart\n", | |
"B,C" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$v\\mathbf{\\hat{i}_x} - l \\dot{\\theta}\\mathbf{\\hat{p}_x}$$" | |
], | |
"text/plain": [ | |
"v*I.x - l*theta'*P.x" | |
] | |
}, | |
"execution_count": 21, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"C.set_vel(I, v * I.x)\n", | |
"\n", | |
"B.set_pos(C, l*P.y)\n", | |
"B.v2pt_theory(C, I, P)\n", | |
"\n", | |
"# optionally: define the origin point and find where the pendulum bob is\n", | |
"#O.set_vel(I,0)\n", | |
"#C.set_pos(O, x * I.x)\n", | |
"#B.pos_from(O).express(I)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left [ \\omega - \\dot{\\theta}\\right ]$$" | |
], | |
"text/plain": [ | |
"[omega - theta']" | |
] | |
}, | |
"execution_count": 22, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"kd = [omega - theta.diff()]\n", | |
"kd" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"F = dynamicsymbols(\"F\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 24, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"[(B, - g*m*I.y), (C, F*I.x)]" | |
] | |
}, | |
"execution_count": 24, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"FL = [(B, -g*m*I.y),\n", | |
" (C, F*I.x)]\n", | |
"FL" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"#define a body, in this case a particle. It's at P and has a mass m.\n", | |
"bob = Particle('bob', B, m)\n", | |
"cart = Particle('cart', C, M)\n", | |
"BL = [bob, cart]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 26, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"# set up kane's method with frame, coordinates, speeds, and kinematical equations\n", | |
"KM = KanesMethod(I, q_ind=[theta], u_ind=[v,omega], kd_eqs=kd)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 27, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"# find kane's equations given forces and bodies\n", | |
"(fr, frstar) = KM.kanes_equations(FL, BL)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 28, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/latex": [ | |
"$$\\left[\\begin{matrix}- l m \\omega^{2} \\operatorname{sin}\\left(\\theta\\right) + l m \\operatorname{cos}\\left(\\theta\\right) \\dot{\\omega} - \\left(M + m\\right) \\dot{v} + F\\\\g l m \\operatorname{sin}\\left(\\theta\\right) - l^{2} m \\dot{\\omega} + l m \\operatorname{cos}\\left(\\theta\\right) \\dot{v}\\end{matrix}\\right]$$" | |
], | |
"text/plain": [ | |
"Matrix([\n", | |
"[-l*m*omega**2*sin(theta) + l*m*cos(theta)*omega' - (M + m)*v' + F],\n", | |
"[ g*l*m*sin(theta) - l**2*m*omega' + l*m*cos(theta)*v']])" | |
] | |
}, | |
"execution_count": 28, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# fun fact: fr + frstart = 0\n", | |
"fr + frstar" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 29, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"# Hearteningly, this is the same result as the first section." | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 2", | |
"language": "python", | |
"name": "python2" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.12" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment