Kano001's picture
Upload 3077 files
6a86ad5 verified
raw
history blame
5.69 kB
from sympy import (zeros, Matrix, symbols, lambdify, sqrt, pi,
simplify)
from sympy.physics.mechanics import (dynamicsymbols, cross, inertia, RigidBody,
ReferenceFrame, KanesMethod)
def _create_rolling_disc():
# Define symbols and coordinates
t = dynamicsymbols._t
q1, q2, q3, q4, q5, u1, u2, u3, u4, u5 = dynamicsymbols('q1:6 u1:6')
g, r, m = symbols('g r m')
# Define bodies and frames
ground = RigidBody('ground')
disc = RigidBody('disk', mass=m)
disc.inertia = (m * r ** 2 / 4 * inertia(disc.frame, 1, 2, 1),
disc.masscenter)
ground.masscenter.set_vel(ground.frame, 0)
disc.masscenter.set_vel(disc.frame, 0)
int_frame = ReferenceFrame('int_frame')
# Orient frames
int_frame.orient_body_fixed(ground.frame, (q1, q2, 0), 'zxy')
disc.frame.orient_axis(int_frame, int_frame.y, q3)
g_w_d = disc.frame.ang_vel_in(ground.frame)
disc.frame.set_ang_vel(ground.frame,
u1 * disc.x + u2 * disc.y + u3 * disc.z)
# Define points
cp = ground.masscenter.locatenew('contact_point',
q4 * ground.x + q5 * ground.y)
cp.set_vel(ground.frame, u4 * ground.x + u5 * ground.y)
disc.masscenter.set_pos(cp, r * int_frame.z)
disc.masscenter.set_vel(ground.frame, cross(
disc.frame.ang_vel_in(ground.frame), disc.masscenter.pos_from(cp)))
# Define kinematic differential equations
kdes = [g_w_d.dot(disc.x) - u1, g_w_d.dot(disc.y) - u2,
g_w_d.dot(disc.z) - u3, q4.diff(t) - u4, q5.diff(t) - u5]
# Define nonholonomic constraints
v0 = cp.vel(ground.frame) + cross(
disc.frame.ang_vel_in(int_frame), cp.pos_from(disc.masscenter))
fnh = [v0.dot(ground.x), v0.dot(ground.y)]
# Define loads
loads = [(disc.masscenter, -disc.mass * g * ground.z)]
bodies = [disc]
return {
'frame': ground.frame,
'q_ind': [q1, q2, q3, q4, q5],
'u_ind': [u1, u2, u3],
'u_dep': [u4, u5],
'kdes': kdes,
'fnh': fnh,
'bodies': bodies,
'loads': loads
}
def _verify_rolling_disc_numerically(kane, all_zero=False):
q, u, p = dynamicsymbols('q1:6'), dynamicsymbols('u1:6'), symbols('g r m')
eval_sys = lambdify((q, u, p), (kane.mass_matrix_full, kane.forcing_full),
cse=True)
solve_sys = lambda q, u, p: Matrix.LUsolve(
*(Matrix(mat) for mat in eval_sys(q, u, p)))
solve_u_dep = lambdify((q, u[:3], p), kane._Ars * Matrix(u[:3]), cse=True)
eps = 1e-10
p_vals = (9.81, 0.26, 3.43)
# First numeric test
q_vals = (0.3, 0.1, 1.97, -0.35, 2.27)
u_vals = [-0.2, 1.3, 0.15]
u_vals.extend(solve_u_dep(q_vals, u_vals, p_vals)[:2, 0])
expected = Matrix([
0.126603940595934, 0.215942571601660, 1.28736069604936,
0.319764288376543, 0.0989146857254898, -0.925848952664489,
-0.0181350656532944, 2.91695398184589, -0.00992793421754526,
0.0412861634829171])
assert all(abs(x) < eps for x in
(solve_sys(q_vals, u_vals, p_vals) - expected))
# Second numeric test
q_vals = (3.97, -0.28, 8.2, -0.35, 2.27)
u_vals = [-0.25, -2.2, 0.62]
u_vals.extend(solve_u_dep(q_vals, u_vals, p_vals)[:2, 0])
expected = Matrix([
0.0259159090798597, 0.668041660387416, -2.19283799213811,
0.385441810852219, 0.420109283790573, 1.45030568179066,
-0.0110924422400793, -8.35617840186040, -0.154098542632173,
-0.146102664410010])
assert all(abs(x) < eps for x in
(solve_sys(q_vals, u_vals, p_vals) - expected))
if all_zero:
q_vals = (0, 0, 0, 0, 0)
u_vals = (0, 0, 0, 0, 0)
assert solve_sys(q_vals, u_vals, p_vals) == zeros(10, 1)
def test_kane_rolling_disc_lu():
props = _create_rolling_disc()
kane = KanesMethod(props['frame'], props['q_ind'], props['u_ind'],
props['kdes'], u_dependent=props['u_dep'],
velocity_constraints=props['fnh'],
bodies=props['bodies'], forcelist=props['loads'],
explicit_kinematics=False, constraint_solver='LU')
kane.kanes_equations()
_verify_rolling_disc_numerically(kane)
def test_kane_rolling_disc_kdes_callable():
props = _create_rolling_disc()
kane = KanesMethod(
props['frame'], props['q_ind'], props['u_ind'], props['kdes'],
u_dependent=props['u_dep'], velocity_constraints=props['fnh'],
bodies=props['bodies'], forcelist=props['loads'],
explicit_kinematics=False,
kd_eqs_solver=lambda A, b: simplify(A.LUsolve(b)))
q, u, p = dynamicsymbols('q1:6'), dynamicsymbols('u1:6'), symbols('g r m')
qd = dynamicsymbols('q1:6', 1)
eval_kdes = lambdify((q, qd, u, p), tuple(kane.kindiffdict().items()))
eps = 1e-10
# Test with only zeros. If 'LU' would be used this would result in nan.
p_vals = (9.81, 0.25, 3.5)
zero_vals = (0, 0, 0, 0, 0)
assert all(abs(qdi - fui) < eps for qdi, fui in
eval_kdes(zero_vals, zero_vals, zero_vals, p_vals))
# Test with some arbitrary values
q_vals = tuple(map(float, (pi / 6, pi / 3, pi / 2, 0.42, 0.62)))
qd_vals = tuple(map(float, (4, 1 / 3, 4 - 2 * sqrt(3),
0.25 * (2 * sqrt(3) - 3),
0.25 * (2 - sqrt(3)))))
u_vals = tuple(map(float, (-2, 4, 1 / 3, 0.25 * (-3 + 2 * sqrt(3)),
0.25 * (-sqrt(3) + 2))))
assert all(abs(qdi - fui) < eps for qdi, fui in
eval_kdes(q_vals, qd_vals, u_vals, p_vals))