123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- #!/usr/bin/env python
- """This module contains some sample symbolic models used for testing and
- examples."""
- # Internal imports
- from sympy.core import backend as sm
- import sympy.physics.mechanics as me
- def multi_mass_spring_damper(n=1, apply_gravity=False,
- apply_external_forces=False):
- r"""Returns a system containing the symbolic equations of motion and
- associated variables for a simple multi-degree of freedom point mass,
- spring, damper system with optional gravitational and external
- specified forces. For example, a two mass system under the influence of
- gravity and external forces looks like:
- ::
- ----------------
- | | | | g
- \ | | | V
- k0 / --- c0 |
- | | | x0, v0
- --------- V
- | m0 | -----
- --------- |
- | | | |
- \ v | | |
- k1 / f0 --- c1 |
- | | | x1, v1
- --------- V
- | m1 | -----
- ---------
- | f1
- V
- Parameters
- ==========
- n : integer
- The number of masses in the serial chain.
- apply_gravity : boolean
- If true, gravity will be applied to each mass.
- apply_external_forces : boolean
- If true, a time varying external force will be applied to each mass.
- Returns
- =======
- kane : sympy.physics.mechanics.kane.KanesMethod
- A KanesMethod object.
- """
- mass = sm.symbols('m:{}'.format(n))
- stiffness = sm.symbols('k:{}'.format(n))
- damping = sm.symbols('c:{}'.format(n))
- acceleration_due_to_gravity = sm.symbols('g')
- coordinates = me.dynamicsymbols('x:{}'.format(n))
- speeds = me.dynamicsymbols('v:{}'.format(n))
- specifieds = me.dynamicsymbols('f:{}'.format(n))
- ceiling = me.ReferenceFrame('N')
- origin = me.Point('origin')
- origin.set_vel(ceiling, 0)
- points = [origin]
- kinematic_equations = []
- particles = []
- forces = []
- for i in range(n):
- center = points[-1].locatenew('center{}'.format(i),
- coordinates[i] * ceiling.x)
- center.set_vel(ceiling, points[-1].vel(ceiling) +
- speeds[i] * ceiling.x)
- points.append(center)
- block = me.Particle('block{}'.format(i), center, mass[i])
- kinematic_equations.append(speeds[i] - coordinates[i].diff())
- total_force = (-stiffness[i] * coordinates[i] -
- damping[i] * speeds[i])
- try:
- total_force += (stiffness[i + 1] * coordinates[i + 1] +
- damping[i + 1] * speeds[i + 1])
- except IndexError: # no force from below on last mass
- pass
- if apply_gravity:
- total_force += mass[i] * acceleration_due_to_gravity
- if apply_external_forces:
- total_force += specifieds[i]
- forces.append((center, total_force * ceiling.x))
- particles.append(block)
- kane = me.KanesMethod(ceiling, q_ind=coordinates, u_ind=speeds,
- kd_eqs=kinematic_equations)
- kane.kanes_equations(particles, forces)
- return kane
- def n_link_pendulum_on_cart(n=1, cart_force=True, joint_torques=False):
- r"""Returns the system containing the symbolic first order equations of
- motion for a 2D n-link pendulum on a sliding cart under the influence of
- gravity.
- ::
- |
- o y v
- \ 0 ^ g
- \ |
- --\-|----
- | \| |
- F-> | o --|---> x
- | |
- ---------
- o o
- Parameters
- ==========
- n : integer
- The number of links in the pendulum.
- cart_force : boolean, default=True
- If true an external specified lateral force is applied to the cart.
- joint_torques : boolean, default=False
- If true joint torques will be added as specified inputs at each
- joint.
- Returns
- =======
- kane : sympy.physics.mechanics.kane.KanesMethod
- A KanesMethod object.
- Notes
- =====
- The degrees of freedom of the system are n + 1, i.e. one for each
- pendulum link and one for the lateral motion of the cart.
- M x' = F, where x = [u0, ..., un+1, q0, ..., qn+1]
- The joint angles are all defined relative to the ground where the x axis
- defines the ground line and the y axis points up. The joint torques are
- applied between each adjacent link and the between the cart and the
- lower link where a positive torque corresponds to positive angle.
- """
- if n <= 0:
- raise ValueError('The number of links must be a positive integer.')
- q = me.dynamicsymbols('q:{}'.format(n + 1))
- u = me.dynamicsymbols('u:{}'.format(n + 1))
- if joint_torques is True:
- T = me.dynamicsymbols('T1:{}'.format(n + 1))
- m = sm.symbols('m:{}'.format(n + 1))
- l = sm.symbols('l:{}'.format(n))
- g, t = sm.symbols('g t')
- I = me.ReferenceFrame('I')
- O = me.Point('O')
- O.set_vel(I, 0)
- P0 = me.Point('P0')
- P0.set_pos(O, q[0] * I.x)
- P0.set_vel(I, u[0] * I.x)
- Pa0 = me.Particle('Pa0', P0, m[0])
- frames = [I]
- points = [P0]
- particles = [Pa0]
- forces = [(P0, -m[0] * g * I.y)]
- kindiffs = [q[0].diff(t) - u[0]]
- if cart_force is True or joint_torques is True:
- specified = []
- else:
- specified = None
- for i in range(n):
- Bi = I.orientnew('B{}'.format(i), 'Axis', [q[i + 1], I.z])
- Bi.set_ang_vel(I, u[i + 1] * I.z)
- frames.append(Bi)
- Pi = points[-1].locatenew('P{}'.format(i + 1), l[i] * Bi.y)
- Pi.v2pt_theory(points[-1], I, Bi)
- points.append(Pi)
- Pai = me.Particle('Pa' + str(i + 1), Pi, m[i + 1])
- particles.append(Pai)
- forces.append((Pi, -m[i + 1] * g * I.y))
- if joint_torques is True:
- specified.append(T[i])
- if i == 0:
- forces.append((I, -T[i] * I.z))
- if i == n - 1:
- forces.append((Bi, T[i] * I.z))
- else:
- forces.append((Bi, T[i] * I.z - T[i + 1] * I.z))
- kindiffs.append(q[i + 1].diff(t) - u[i + 1])
- if cart_force is True:
- F = me.dynamicsymbols('F')
- forces.append((P0, F * I.x))
- specified.append(F)
- kane = me.KanesMethod(I, q_ind=q, u_ind=u, kd_eqs=kindiffs)
- kane.kanes_equations(particles, forces)
- return kane
|