@@ -481,25 +481,71 @@ void QuaternionFloatingMobilizer<T>::DoMapAccelerationToQDDot(
481
481
const Eigen::Ref<const VectorX<T>>& vdot,
482
482
EigenPtr<VectorX<T>> qddot) const {
483
483
// This function maps vdot to qddot by calculating q̈ = Ṅ(q,q̇)⋅v + N(q)⋅v̇.
484
- // It first calculates the rotational parts , then the translational part.
484
+ // It first calculates the rotational part , then the translational part.
485
485
//
486
- // Calculate the 2nd-derivative of the quaternion q_FM = [qw, qx, qy, qz]ᵀ.
487
- // q̈_FM = Nᵣ(q) [ẇx, ẇy, ẇz]ᵀ - 0.25 ω² q_FM, where ω² = |w_FM|².
488
- // Formulas and proofs in Section 9.3 of [Mitiguy, August 2019].
489
- // [Mitiguy, August 2019] Mitiguy, P. Advanced Dynamics & Motion Simulation.
490
- // Available at www.MotionGenesis.com
486
+ // For the rotational part of this mobilizer, the 2nd-derivatives of the
487
+ // generalized positions q̈_FM = q̈ᵣ = [q̈w, q̈x, q̈y, q̈z]ᵀ are related to the
488
+ // 1st-derivatives of the generalized velocities ẇ_FM_F = v̇ᵣ = [ẇx, ẇy, ẇz]ᵀ
489
+ // as q̈_FM = Ṅᵣ(q,q̇)⋅v + Nᵣ(q)⋅v̇, where Nᵣ(q) is the 3x4 matrix below and
490
+ // Ṅᵣ(q,q̇)⋅v = -0.25 ω² q_FM, where ω² = |w_FM_F|² and w_FM_F = [wx, wy, wz]ᵀ.
491
+ //
492
+ // ⌈ q̈w ⌉ ⌈ -qx -qy -qz ⌉ ⌈ ẇx ⌉ ⌈ qw ⌉
493
+ // | q̈x | = 0.5 | qw qz -qy | | ẇy | - 0.25 ω² | qx |
494
+ // | q̈y | | qw qw qx | ⌊ ẇz ⌋ | qy |
495
+ // ⌊ q̈z ⌋ ⌊ qy -qx qw ⌋ ⌊ qz ⌋
496
+ //
497
+ // Formulas and proofs in Sections 9.3 and 9.6 of [Mitiguy, August 2025].
498
+ // [Mitiguy, August 2025] Mitiguy, P. Advanced Dynamics & Motion Simulation.
499
+ // Textbook available at www.MotionGenesis.com
491
500
const Quaternion<T> q_FM = get_quaternion (context);
492
501
const Vector3<T> w_FM_F = get_angular_velocity (context);
493
502
const T w_squared_over_four = 0.25 * w_FM_F.squaredNorm ();
494
503
qddot->template head <4 >() =
495
504
AngularVelocityToQuaternionRateMatrix (q_FM) * vdot.template head <3 >() -
496
505
w_squared_over_four * Vector4<T>(q_FM.w (), q_FM.x (), q_FM.y (), q_FM.z ());
497
506
498
- // Calculate the 2nd-derivtive of the position vector p_FoMo_F = [x, y, z]ᵀ.
507
+ // Calculate the 2nd-derivative of the position vector p_FoMo_F = [x, y, z]ᵀ
508
+ // in terms of 1st-derivative of the velocity v_FoM_F = [vx, vy, vz]ᵀ as
499
509
// [ẍ, ÿ, z̈]ᵀ = [v̇x, v̇y, v̇z]ᵀ.
500
510
qddot->template tail <3 >() = vdot.template tail <3 >();
501
511
}
502
512
513
+ template <typename T>
514
+ void DoMapQDDotToAcceleration (const systems::Context<T>& context,
515
+ const Eigen::Ref<const VectorX<T>>& qddot,
516
+ EigenPtr<VectorX<T>> vdot) {
517
+ // This function maps qddot to vdot by calculating v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈.
518
+ // It first calculates the rotational part, then the translational part.
519
+ //
520
+ // For the rotational part of this mobilizer, the 1st-derivatives of the
521
+ // generalized velocities ẇ_FM_F = v̇ᵣ = [ẇx, ẇy, ẇz]ᵀ are related to the
522
+ // 2nd-derivatives of the generalized positions q̈̇_FM = q̇ᵣ = [q̈w, q̈x, q̈y, q̈z]ᵀ
523
+ // as v̇ᵣ = N⁺ᵣ(q)⋅q̈_FM, where N⁺ᵣ(q) is the 3x4 matrix below.
524
+ // Note: Perhaps surprisingly, Ṅ⁺ᵣ(q,q̇)⋅q̇ = [0, 0, 0]ᵀ.
525
+ //
526
+ // ⌈ ẇx ⌉ ⌈ -qx qw -qz -qy ⌉ ⌈ q̈w ⌉
527
+ // | ẇy | = 2.0 | -qy qz qw -qx | | q̈x |
528
+ // ⌊ ẇz ⌋ | -qz -qy qx qw | | q̈y |
529
+ // ⌊ q̈z ⌋
530
+ //
531
+ // Formulas and proofs in Sections 9.3 and 9.6 of [Mitiguy, August 2025].
532
+ // [Mitiguy, August 2025] Mitiguy, P. Advanced Dynamics & Motion Simulation.
533
+ // Textbook available at www.MotionGenesis.com
534
+
535
+ // Since QuaternionRateToAngularVelocityMatrix() calculates N⁺ᵣ(qᵣ), we use
536
+ // this function to calculate v̇ᵣ = N⁺ᵣ(q)⋅q̈_FM.
537
+ const Quaternion<T> q_FM = get_quaternion (context);
538
+ vdot->template head <3 >() =
539
+ QuaternionRateToAngularVelocityMatrix (q_FM) * qddot.template head <4 >();
540
+
541
+ // For the translational part of this mobilizer, the 1st-derivatives of the
542
+ // translational generalized velocities v̇_FM_F = v̇ₜ = [v̇x, v̇y, v̇z]ᵀ are
543
+ // related to the 2nd-derivatives of the generalized positions q̈ₜ = [ẍ, ÿ, z̈]ᵀ
544
+ // as v̇ₜ = N⁺ₜ(q)⋅q̈ₜ, where Nₜ(q) = [I₃₃] (3x3 identity matrix), i.e., as
545
+ // [v̇x, v̇y, v̇z]ᵀ = [ẍ, ÿ, z̈]ᵀ.
546
+ vdot->template tail <3 >() = qddot.template tail <3 >();
547
+ }
548
+
503
549
template <typename T>
504
550
std::pair<Eigen::Quaternion<T>, Vector3<T>>
505
551
QuaternionFloatingMobilizer<T>::GetPosePair(
0 commit comments