Skip to content

Commit cea4f92

Browse files
Rebase: Mysterious negative sign required sometimes #105 (#200)
* Bugfix: Transpose rotation matrices to fix the direction of the rotation * Get rid of neg_w * Update unit tests --------- Co-authored-by: ElMapacheDelOeste <[email protected]>
1 parent 30f0a96 commit cea4f92

File tree

8 files changed

+47
-58
lines changed

8 files changed

+47
-58
lines changed

src/components.jl

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,6 @@ This component has a single frame, `frame_a`. To represent bodies with more than
376376
isroot = false,
377377
state = false,
378378
sequence = [1,2,3],
379-
neg_w = true,
380379
phi0 = zeros(3),
381380
phid0 = zeros(3),
382381
r_0 = state || isroot ? 0 : nothing,
@@ -456,7 +455,7 @@ This component has a single frame, `frame_a`. To represent bodies with more than
456455
if quat
457456
@named frame_a = Frame(varw=false)
458457
Ra = ori(frame_a, false)
459-
qeeqs = nonunit_quaternion_equations(Ra, w_a; neg_w)
458+
qeeqs = nonunit_quaternion_equations(Ra, w_a)
460459
else
461460
@named frame_a = Frame(varw=true)
462461
Ra = ori(frame_a, true)
@@ -469,13 +468,8 @@ This component has a single frame, `frame_a`. To represent bodies with more than
469468
phid .~ D.(phi)
470469
phidd .~ D.(phid)
471470
Ra.w .~ ar.w
472-
if neg_w
473-
# w_a .~ -ar.w # This is required for FreeBody and ThreeSprings tests to pass, but the other one required for harmonic osciallator without joint to pass. FreeBody passes with quat=true so we use that instead
474-
collect(w_a .~ -angular_velocity2(ar))
475-
else
476-
collect(w_a .~ (angular_velocity2(ar)))
471+
collect(w_a .~ (angular_velocity2(ar)))
477472
# w_a .~ ar.w # This one for most systems
478-
end
479473
Ra ~ ar
480474
]
481475
end
@@ -788,7 +782,7 @@ Rigid body with cylinder shape. The mass properties of the body (mass, center of
788782
- `a_0`: Absolute acceleration of `frame_a` resolved in world frame (= D(v_0))
789783
"""
790784
@component function BodyCylinder(; name, r = [1, 0, 0], r_shape = [0, 0, 0], isroot = false,
791-
state = false, quat = false, sequence = [1, 2, 3], neg_w = true,
785+
state = false, quat = false, sequence = [1, 2, 3],
792786
diameter = 1, inner_diameter = 0, density = 7700, color = purple)
793787
pars = @parameters begin
794788
dir[1:3] = r - r_shape, [description = "Vector in length direction of cylinder, resolved in frame_a"]
@@ -815,7 +809,7 @@ Rigid body with cylinder shape. The mass properties of the body (mass, center of
815809
frame_a = Frame()
816810
frame_b = Frame()
817811
translation = FixedTranslation(r = r)
818-
body = Body(; m, r_cm, I_11 = I[1,1], I_22 = I[2,2], I_33 = I[3,3], I_21 = I[2,1], I_31 = I[3,1], I_32 = I[3,2], state, quat, isroot, sequence, neg_w, sparse_I=true)
812+
body = Body(; m, r_cm, I_11 = I[1,1], I_22 = I[2,2], I_33 = I[3,3], I_21 = I[2,1], I_31 = I[3,1], I_32 = I[3,2], state, quat, isroot, sequence, sparse_I=true)
819813
end
820814

821815
vars = @variables begin

src/joints.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ Joint with 3 constraints that define that the origin of `frame_a` and the origin
181181
z_rel_a_fixed = false, sequence = [1, 2, 3], phi = 0,
182182
phid = 0,
183183
d = 0,
184-
neg_w = true,
185184
phidd = 0,
186185
color = [1, 1, 0, 1],
187186
radius = 0.1,
@@ -224,7 +223,7 @@ Joint with 3 constraints that define that the origin of `frame_a` and the origin
224223

225224
if state
226225
if quat
227-
append!(eqs, nonunit_quaternion_equations(Rrel, w_rel; neg_w))
226+
append!(eqs, nonunit_quaternion_equations(Rrel, w_rel))
228227
# append!(eqs, collect(w_rel) .~ angularVelocity2(Rrel))
229228
else
230229
@variables begin
@@ -485,7 +484,6 @@ The relative position vector `r_rel_a` from the origin of `frame_a` to the origi
485484
state_priority = 4,
486485
phid = 0,
487486
phidd = nothing,
488-
neg_w = true,
489487
w_rel_b = 0,
490488
r_rel_a = 0,
491489
v_rel_a = 0,
@@ -546,14 +544,14 @@ The relative position vector `r_rel_a` from the origin of `frame_a` to the origi
546544
end
547545

548546
if quat
549-
append!(eqs, nonunit_quaternion_equations(Rrel, w_rel_b; neg_w))
547+
append!(eqs, nonunit_quaternion_equations(Rrel, w_rel_b))
550548

551549
else
552550
append!(eqs,
553551
[phid .~ D.(phi)
554552
phidd .~ D.(phid)
555553
Rrel ~ axes_rotations(sequence, phi, phid)
556-
w_rel_b .~ (neg_w ? -1 : 1) * angular_velocity2(Rrel)])
554+
w_rel_b .~ angular_velocity2(Rrel)])
557555
end
558556

559557
else

src/orientation.jl

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ function from_Q(Q2, w; normalize=false)
262262
Q2 = Q2 / _norm(Q2)
263263
end
264264
q = Rotations.QuatRotation(Q2, false)
265-
R = RotMatrix(q)
265+
R = RotMatrix(q)'
266266
RotationMatrix(R, w)
267267
end
268268

@@ -313,11 +313,11 @@ Returns a `RotationMatrix` object.
313313
"""
314314
function axis_rotation(sequence, angle; name = :R)
315315
if sequence == 1
316-
return RotationMatrix(Rotations.RotX(angle), zeros(3))
316+
return RotationMatrix(Rotations.RotX(angle)', zeros(3))
317317
elseif sequence == 2
318-
return RotationMatrix(Rotations.RotY(angle), zeros(3))
318+
return RotationMatrix(Rotations.RotY(angle)', zeros(3))
319319
elseif sequence == 3
320-
return RotationMatrix(Rotations.RotZ(angle), zeros(3))
320+
return RotationMatrix(Rotations.RotZ(angle)', zeros(3))
321321
else
322322
error("Invalid sequence $sequence")
323323
end
@@ -436,7 +436,7 @@ function get_frame(sol, frame, t)
436436
[R tr; 0 0 0 1]
437437
end
438438

439-
function nonunit_quaternion_equations(R, w; neg_w = true)
439+
function nonunit_quaternion_equations(R, w)
440440
@variables Q(t)[1:4]=[1,0,0,0], [state_priority=-1, description="Unit quaternion with [w,i,j,k]"] # normalized
441441
@variables (t)[1:4]=[1,0,0,0], [state_priority=1000, description="Non-unit quaternion with [w,i,j,k]"] # Non-normalized
442442
@variables Q̂d(t)[1:4]=[0,0,0,0], [state_priority=1000]
@@ -452,9 +452,6 @@ function nonunit_quaternion_equations(R, w; neg_w = true)
452452
# where angularVelocity2(Q, der(Q)) = 2*([Q[4] Q[3] -Q[2] -Q[1]; -Q[3] Q[4] Q[1] -Q[2]; Q[2] -Q[1] Q[4] -Q[3]]*der_Q)
453453
# They also have w_a = angularVelocity2(frame_a.R) even for quaternions, so w_a = angularVelocity2(Q, der(Q)), this is their link between w_a and D(Q), while ours is D(Q̂) .~ (Ω * Q̂)
454454
Ω = [0 -w[1] -w[2] -w[3]; w[1] 0 w[3] -w[2]; w[2] -w[3] 0 w[1]; w[3] w[2] -w[1] 0]
455-
if neg_w
456-
Ω = Ω'
457-
end
458455

459456
# QR = from_Q(Q, angular_velocity2(Q, D.(Q)))
460457
QR = from_Q(Q̂ ./ sqrt(n), w)

src/wheels.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ this frame.
117117
@named frame_a = Frame(varw=true)
118118
Ra = ori(frame_a, true)
119119

120-
Rarot = axes_rotations(sequence, angles, -der_angles) # The - is the neg_w change
120+
Rarot = axes_rotations(sequence, angles, der_angles)
121121

122122
equations = if surface === nothing
123123
[ # Road description
@@ -400,7 +400,7 @@ plot!(
400400
@named frame_a = Frame(varw=state)
401401
Ra = ori(frame_a, state)
402402

403-
Rarot = axes_rotations(sequence, angles, -der_angles) # The - is the neg_w change
403+
Rarot = axes_rotations(sequence, angles, der_angles)
404404

405405
equations = if surface === nothing
406406
[ # Road description

test/runtests.jl

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ t = Multibody.t
6868
D = Differential(t)
6969
@testset "spring - harmonic oscillator" begin
7070

71-
@named body = Body(; m = 1, isroot = true, r_cm = [0, -1, 0], quat=true, neg_w=true) # This time the body isroot since there is no joint containing state
71+
@named body = Body(; m = 1, isroot = true, r_cm = [0, -1, 0], quat=true) # This time the body isroot since there is no joint containing state
7272
@named spring = Multibody.Spring(c = 1)
7373

7474
connections = [connect(world.frame_b, spring.frame_a)
@@ -989,7 +989,16 @@ prob = ODEProblem(ssys, [
989989
collect(body.w_a) .=> [1,1,1];
990990
collect(body.v_0) .=> [10,10,10]
991991
], (0, 10))
992-
@time "Flexible rope pendulum" sol = solve(prob, Rodas4(autodiff=false); u0 = prob.u0 .+ 0.5);
992+
@time "Flexible rope pendulum" sol = solve(prob, Rodas4(autodiff=false); u0 = prob.u0 .+ [-0.5, -0.5, -0.5,
993+
-0.5, -0.5, -0.5,
994+
-0.5, -0.5, -0.5,
995+
0.5, 0.5, 0.5,
996+
-0.5, -0.5, -0.5,
997+
-0.5, -0.5, -0.5,
998+
-0.5, -0.5, -0.5,
999+
-0.5, -0.5, -0.5,
1000+
0.5, 0.5, 0.5,
1001+
-0.5, -0.5, -0.5]);
9931002
@test SciMLBase.successful_retcode(sol)
9941003
if false
9951004
import GLMakie
@@ -1008,7 +1017,7 @@ end
10081017

10091018
systems = @named begin
10101019
joint = Spherical(state=true, isroot=true, phi =/2, 0, 0], d = 0.3)
1011-
bar = FixedTranslation(r = [0, -1, 0])
1020+
bar = FixedTranslation(r = [0, 1, 0])
10121021
body = Body(; m = 1, isroot = false)
10131022

10141023

@@ -1200,7 +1209,7 @@ world = Multibody.world
12001209

12011210
@named joint = Multibody.Spherical(isroot=false, state=false, quat=false)
12021211
@named rod = FixedTranslation(; r = [1, 0, 0])
1203-
@named body = Body(; m = 1, isroot=true, quat=true, neg_w=true)
1212+
@named body = Body(; m = 1, isroot=true, quat=true)
12041213

12051214
connections = [connect(world.frame_b, joint.frame_a)
12061215
connect(joint.frame_b, rod.frame_a)
@@ -1219,7 +1228,7 @@ sol1 = solve(prob, FBDF(), abstol=1e-8, reltol=1e-8)
12191228
@test SciMLBase.successful_retcode(sol1)
12201229

12211230
## quat in joint
1222-
@named joint = Multibody.Spherical(isroot=true, state=true, quat=true, neg_w=true)
1231+
@named joint = Multibody.Spherical(isroot=true, state=true, quat=true)
12231232
@named rod = FixedTranslation(; r = [1, 0, 0])
12241233
@named body = Body(; m = 1, isroot=false, quat=false)
12251234

@@ -1240,7 +1249,7 @@ sol2 = solve(prob, FBDF(), abstol=1e-8, reltol=1e-8)
12401249
@test SciMLBase.successful_retcode(sol2)
12411250

12421251
## euler
1243-
@named joint = Multibody.Spherical(isroot=true, state=true, quat=false, neg_w=true)
1252+
@named joint = Multibody.Spherical(isroot=true, state=true, quat=false)
12441253
@named rod = FixedTranslation(; r = [1, 0, 0])
12451254
@named body = Body(; m = 1, isroot=false, quat=false)
12461255

test/test_quaternions.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ using OrdinaryDiffEq, Test
7878

7979
t = Multibody.t
8080
@named joint = Multibody.FreeMotion(isroot = true, state=false)
81-
@named body = Body(; m = 1, r_cm = [0.0, 0, 0], isroot=true, quat=true, w_a=[1,0.5,0.2], neg_w=true)
81+
@named body = Body(; m = 1, r_cm = [0.0, 0, 0], isroot=true, quat=true, w_a=[1,0.5,0.2])
8282

8383
# @named joint = Multibody.FreeMotion(isroot = true, state=true, quat=true)
8484
# @named body = Body(; m = 1, r_cm = [0.0, 0, 0], isroot=false, w_a=[1,1,1])
@@ -152,7 +152,7 @@ end
152152
t = Multibody.t
153153
world = Multibody.world
154154

155-
@named joint = Multibody.FreeMotion(isroot = true, state=true, quat=true, neg_w=true)
155+
@named joint = Multibody.FreeMotion(isroot = true, state=true, quat=true)
156156
@named body = Body(; m = 1, r_cm = [0.0, 0, 0])
157157

158158
connections = [connect(world.frame_b, joint.frame_a)
@@ -206,7 +206,7 @@ end
206206

207207
@named joint = Multibody.Spherical(isroot=false, state=false, quat=false)
208208
@named rod = FixedTranslation(; r = [1, 0, 0])
209-
@named body = Body(; m = 1, isroot=true, quat=true, air_resistance=0.0, neg_w=true)
209+
@named body = Body(; m = 1, isroot=true, quat=true, air_resistance=0.0)
210210

211211
# @named joint = Multibody.Spherical(isroot=true, state=true, quat=true)
212212
# @named body = Body(; m = 1, r_cm = [1.0, 0, 0], isroot=false)
@@ -275,7 +275,7 @@ using Multibody.Rotations: params
275275

276276
@named begin
277277
body = BodyShape(m = 1, I_11 = 1, I_22 = 1, I_33 = 1, r = [0.4, 0, 0],
278-
r_0 = [0.2, -0.5, 0.1], r_cm = [0.2, 0, 0], isroot = true, quat=true, neg_w=true)
278+
r_0 = [0.2, -0.5, 0.1], r_cm = [0.2, 0, 0], isroot = true, quat=true)
279279
bar2 = FixedTranslation(r = [0.8, 0, 0])
280280
spring1 = Multibody.Spring(c = 20, s_unstretched = 0)
281281
spring2 = Multibody.Spring(c = 20, s_unstretched = 0)

test/test_wheels.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ using LinearAlgebra
1313
I_long = 0.12,
1414
x0 = 0.2,
1515
z0 = 0.2,
16-
der_angles = [0, 5, 1])
16+
der_angles = [0, -5, -1])
1717
end
1818

1919
pars = @parameters begin
@@ -95,7 +95,7 @@ defs = Dict([
9595
worldwheel.wheel.body.r_0[1] => 0.2;
9696
worldwheel.wheel.body.r_0[2] => 0.3;
9797
worldwheel.wheel.body.r_0[3] => 0.2;
98-
collect(worldwheel.wheel.wheeljoint.der_angles) .=> [0, 5, 1];
98+
collect(worldwheel.wheel.wheeljoint.der_angles) .=> [0, -5, -1];
9999
# collect(D.(cwheel.wheel.angles)) .=> [0, 5, 1]
100100
])
101101

@@ -152,7 +152,7 @@ import ModelingToolkitStandardLibrary.Blocks
152152
x0 = 1,
153153
z0 = 1,
154154
iscut=true,
155-
der_angles = [0, 5, 0])
155+
der_angles = [0, -5, 0])
156156
end
157157

158158
pars = @parameters begin

0 commit comments

Comments
 (0)