Skip to content

Commit cc36e31

Browse files
author
Paul Mitiguy
committed
Partial update with new function implemented -- which copious comments.
1 parent 1274cf8 commit cc36e31

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

multibody/tree/quaternion_floating_mobilizer.cc

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -481,25 +481,71 @@ void QuaternionFloatingMobilizer<T>::DoMapAccelerationToQDDot(
481481
const Eigen::Ref<const VectorX<T>>& vdot,
482482
EigenPtr<VectorX<T>> qddot) const {
483483
// 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.
485485
//
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
491500
const Quaternion<T> q_FM = get_quaternion(context);
492501
const Vector3<T> w_FM_F = get_angular_velocity(context);
493502
const T w_squared_over_four = 0.25 * w_FM_F.squaredNorm();
494503
qddot->template head<4>() =
495504
AngularVelocityToQuaternionRateMatrix(q_FM) * vdot.template head<3>() -
496505
w_squared_over_four * Vector4<T>(q_FM.w(), q_FM.x(), q_FM.y(), q_FM.z());
497506

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
499509
// [ẍ, ÿ, z̈]ᵀ = [v̇x, v̇y, v̇z]ᵀ.
500510
qddot->template tail<3>() = vdot.template tail<3>();
501511
}
502512

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+
503549
template <typename T>
504550
std::pair<Eigen::Quaternion<T>, Vector3<T>>
505551
QuaternionFloatingMobilizer<T>::GetPosePair(

multibody/tree/quaternion_floating_mobilizer.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,10 @@ class QuaternionFloatingMobilizer final : public MobilizerImpl<T, 7, 6> {
316316
void DoMapAccelerationToQDDot(const systems::Context<T>& context,
317317
const Eigen::Ref<const VectorX<T>>& vdot,
318318
EigenPtr<VectorX<T>> qddot) const final;
319-
#if 0
320-
// Maps qddot to vdot by calculating v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈.
319+
321320
void DoMapQDDotToAcceleration(const systems::Context<T>& context,
322321
const Eigen::Ref<const VectorX<T>>& qddot,
323322
EigenPtr<VectorX<T>> vdot) const final;
324-
#endif
325323

326324
std::unique_ptr<Mobilizer<double>> DoCloneToScalar(
327325
const MultibodyTree<double>& tree_clone) const final;

0 commit comments

Comments
 (0)