Skip to content

Commit e74e740

Browse files
author
Paul Mitiguy
committed
Improve comments.
1 parent b784c91 commit e74e740

File tree

2 files changed

+20
-22
lines changed

2 files changed

+20
-22
lines changed

multibody/tree/quaternion_floating_mobilizer.cc

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ Eigen::Matrix<T, 4, 3> QuaternionFloatingMobilizer<T>::CalcLMatrix(
292292
// component of the quaternion (Euler parameters). Notice however here we use
293293
// qs and qv for the "scalar" and "vector" components of the quaternion q_FM,
294294
// respectively, while Mitiguy uses ε₀ and ε (in bold), respectively.
295-
// This mobilizer is parameterized by the angular velocity w_FM-F, i.e. time
295+
// This mobilizer is parameterized by the angular velocity w_FM_F, i.e. time
296296
// derivatives of the vector component of the quaternion are taken in the F
297297
// frame. If you are confused by this, notice that the vector component of a
298298
// quaternion IS a vector, and therefore you must specify in what frame time
@@ -301,11 +301,12 @@ Eigen::Matrix<T, 4, 3> QuaternionFloatingMobilizer<T>::CalcLMatrix(
301301
// Notice this is equivalent to:
302302
// Dt_F(q_FM) = 1/2 * w_FM⋅q_FM, where ⋅ denotes the "quaternion product" and
303303
// both the vector component qv_FM of q_FM and w_FM are expressed in frame F.
304-
// Dt_F(q) is short for [Dt_F(q)]_F.
304+
// Using Dt_F(q) as an abbreviation of [Dt_F(q_FM)]_F.
305305
// The expression above can be written as:
306306
// Dt_F(q) = 1/2 * (-w_FM.dot(qv_F); qs * w_FM + w_FM.cross(qv_F))
307307
// = 1/2 * (-w_FM.dot(qv_F); qs * w_FM - qv_F.cross(w_FM))
308308
// = 1/2 * (-w_FM.dot(qv_F); (qs * Id - [qv_F]x) * w_FM)
309+
// = 1/2 * L(q_FM) * w_FM
309310
// = L(q_FM/2) * w_FM
310311
// That is:
311312
// | -qv_Fᵀ | ⌈ -qx -qy -qz ⌉
@@ -401,8 +402,7 @@ void QuaternionFloatingMobilizer<T>::DoCalcNDotMatrix(
401402
const Vector4<T> qdot = CalcLMatrixOverTwo(q_FM) * w_FM_F;
402403
const Quaternion<T> qdot_FM(qdot[0], qdot[1], qdot[2], qdot[3]);
403404

404-
// Leveraging comments and code in CalcLMatrixOverTwo() and noting that
405-
// Nᵣ(qᵣ) = 0.5 * L(q_FM), where the elements of the matrix L are linear in
405+
// Since Nᵣ(qᵣ) = 0.5 * L(q_FM), where L(q_FM) is linear in the elements of
406406
// q_FM = [qw, qx, qy, qz]ᵀ, so Ṅᵣ(qᵣ,q̇ᵣ) = 0.5 * L(q̇_FM).
407407
const Eigen::Matrix<T, 4, 3> NrDotMatrix = CalcLMatrixOverTwo(qdot_FM);
408408

@@ -438,8 +438,8 @@ void QuaternionFloatingMobilizer<T>::DoCalcNplusDotMatrix(
438438
const Vector4<T> qdot = CalcLMatrixOverTwo(q_FM) * w_FM_F;
439439
const Quaternion<T> qdot_FM(qdot[0], qdot[1], qdot[2], qdot[3]);
440440

441-
// Since N⁺ᵣ(qᵣ) = 2 * L(q_FM)ᵀ, where L(q_FM) is linear in q_FM, hence
442-
// Ṅ⁺ᵣ(qᵣ,q̇ᵣ) = 2 * L(q̇_FM)ᵀ.
441+
// Since N⁺ᵣ(qᵣ) = 2 * L(q_FM)ᵀ, where L(q_FM) is linear in the elements of
442+
// q_FM = [qw, qx, qy, qz]ᵀq_FM, hence Ṅ⁺ᵣ(qᵣ,q̇ᵣ) = 2 * L(q̇_FM)ᵀ.
443443
const Eigen::Matrix<T, 3, 4> NrPlusDot =
444444
CalcTwoTimesLMatrixTranspose(qdot_FM);
445445

@@ -482,15 +482,13 @@ void QuaternionFloatingMobilizer<T>::DoMapAccelerationToQDDot(
482482
// It first calculates the rotational part, then the translational part.
483483
//
484484
// For the rotational part of this mobilizer, the 2nd-derivatives of the
485-
// generalized positions q̈_FM = q̈ᵣ = [q̈w, q̈x, q̈y, q̈z]ᵀ are related to the
486-
// 1st-derivatives of the generalized velocities ẇ_FM_F = v̇ᵣ = [ẇx, ẇy, ẇz]ᵀ
487-
// as q̈_FM = Ṅᵣ(q,q̇)⋅v + Nᵣ(q)⋅v̇, where Nᵣ(q) is the 3x4 matrix below and
488-
// Ṅᵣ(q,q̇)⋅v = -0.25 ω² q_FM, where ω² = |w_FM_F|² and w_FM_F = [wx, wy, wz]ᵀ.
485+
// generalized positions q̈_FM = [q̈w, q̈x, q̈y, q̈z]ᵀ are related to the
486+
// 1st-derivatives of generalized velocities ω̇ = ẇ_FM_F = [ω̇x, ω̇y, ω̇z]ᵀ as
487+
// shown below where L(q_FM) is the 4x3 matrix documented in CalcLMatrix(),
488+
// ω = [ωx, ωy, ωz]ᵀ, ω² = |ω|², and 0.5 L̇(q̇_FM)⋅ω = -0.25 ω² q_FM.
489489
//
490-
// ⌈ q̈w ⌉ ⌈ -qx -qy -qz ⌉ ⌈ ẇx ⌉ ⌈ qw ⌉
491-
// | q̈x | = 0.5 | qw qz -qy | | ẇy | - 0.25 ω² | qx |
492-
// | q̈y | | qw qw qx | ⌊ ẇz ⌋ | qy |
493-
// ⌊ q̈z ⌋ ⌊ qy -qx qw ⌋ ⌊ qz ⌋
490+
// q̈_FM = 0.5 L(q_FM)⋅ω̇ + 0.5 L̇(q̇_FM)⋅ω
491+
// = 0.5 L(q_FM)⋅ω̇ - 0.25 ω² q_FM
494492
//
495493
// Formulas and proofs in Sections 9.3 and 9.6 of [Mitiguy, August 2025].
496494
// [Mitiguy, August 2025] Mitiguy, P. Advanced Dynamics & Motion Simulation.

multibody/tree/quaternion_floating_mobilizer.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -339,29 +339,29 @@ class QuaternionFloatingMobilizer final : public MobilizerImpl<T, 7, 6> {
339339
// | -qz qw qx |
340340
// ⌊ qy -qx qw ⌋
341341
//
342-
// The matrix L(q_FM) is an intermediary for various quaternion-related
342+
// Note: The matrix L(q_FM) is an intermediary for various quaternion-related
343343
// calculations. For example, denoting w_FM_F = [ωx, ωy, ωz]ᵀ as frame M's
344-
// angular velocity in frame F, expressed in F, the following involve L(q_FM):
344+
// angular velocity in frame F, expressed in F, the rotational part of the N
345+
// and N⁺ matrices are 0.5 * L(q_FM) and 2 * L(q_FM)ᵀ, respectively. Others:
345346
//
346347
// q̇_FM = 0.5 * L(q_FM) * w_FM_F
347348
// q̈_FM = 0.5 * L(q_FM) * ẇ_FM_F - 0.25 ω² q_FM Note: ω² = |w_FM_F|²
348349
// w_FM_F = 2 * L(q_FM)ᵀ * q̇_FM
349350
// ẇ_FM_F = 2 * L(q_FM)ᵀ * q̇_FM
350-
// Nᵣ(q_FM) = 0.5 * L(q_FM) Nᵣ is the rotational part of the N matrix.
351-
// N⁺ᵣ(q_FM) = 2 * L(q_FM)ᵀ N⁺ᵣ is the rotational part of the Nplus matrix.
351+
//
352+
// Note: Since L(q_FM) depends linearly on q_FM, s * L(q_FM) = L(s * q_FM),
353+
// where s is a scalar (e.g., 0.5 or 2).
352354
static Eigen::Matrix<T, 4, 3> CalcLMatrix(const Quaternion<T>& q);
353355

354356
// Returns the 4x3 matrix 0.5 * L(q_FM), where q_FM = [qw, qx, qy, qz] is the
355-
// quaternion relating frames F and M. As documented in CalcLMatrix(),
356-
// L(q_FM) depends linearly on q_FM, so 0.5 * L(q_FM) = L(0.5 * q_FM).
357+
// quaternion relating frames F and M. See documentation in CalcLMatrix(),
357358
static Eigen::Matrix<T, 4, 3> CalcLMatrixOverTwo(const Quaternion<T>& q_FM) {
358359
return CalcLMatrix(
359360
{0.5 * q_FM.w(), 0.5 * q_FM.x(), 0.5 * q_FM.y(), 0.5 * q_FM.z()});
360361
}
361362

362363
// Returns the 3x4 matrix 2 * L(q_FM)ᵀ, where q_FM = [qw, qx, qy, qz] is the
363-
// quaternion relating frames F and M. As documented in CalcLMatrix(),
364-
// L(q_FM) depends linearly on q_FM, so 2 * L(q_FM)ᵀ = L(2 * q_FM)ᵀ.
364+
// quaternion relating frames F and M. See documentation in CalcLMatrix().
365365
static Eigen::Matrix<T, 3, 4> CalcTwoTimesLMatrixTranspose(
366366
const Quaternion<T>& q_FM) {
367367
return CalcLMatrix({2 * q_FM.w(), 2 * q_FM.x(), 2 * q_FM.y(), 2 * q_FM.z()})

0 commit comments

Comments
 (0)