Skip to content

Commit 1274cf8

Browse files
author
Paul Mitiguy
committed
MapQDDotToAcceleration() and MapAccelerationToQDDot().
1 parent 218b815 commit 1274cf8

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

multibody/tree/quaternion_floating_mobilizer.cc

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,6 @@ Eigen::Matrix<T, 4, 3> QuaternionFloatingMobilizer<T>::CalcLMatrix(
321321
.finished();
322322
}
323323

324-
template <typename T>
325-
Eigen::Matrix<T, 4, 3>
326-
QuaternionFloatingMobilizer<T>::AngularVelocityToQuaternionRateMatrix(
327-
const Quaternion<T>& q_FM) {
328-
// With L given by CalcLMatrix we have:
329-
// N(q) = L(q_FM/2)
330-
return CalcLMatrix(
331-
{q_FM.w() / 2.0, q_FM.x() / 2.0, q_FM.y() / 2.0, q_FM.z() / 2.0});
332-
}
333-
334324
template <typename T>
335325
Eigen::Matrix<T, 3, 4>
336326
QuaternionFloatingMobilizer<T>::QuaternionRateToAngularVelocityMatrix(
@@ -485,6 +475,31 @@ void QuaternionFloatingMobilizer<T>::DoMapQDotToVelocity(
485475
v->template tail<3>() = qdot.template tail<3>();
486476
}
487477

478+
template <typename T>
479+
void QuaternionFloatingMobilizer<T>::DoMapAccelerationToQDDot(
480+
const systems::Context<T>& context,
481+
const Eigen::Ref<const VectorX<T>>& vdot,
482+
EigenPtr<VectorX<T>> qddot) const {
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.
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
491+
const Quaternion<T> q_FM = get_quaternion(context);
492+
const Vector3<T> w_FM_F = get_angular_velocity(context);
493+
const T w_squared_over_four = 0.25 * w_FM_F.squaredNorm();
494+
qddot->template head<4>() =
495+
AngularVelocityToQuaternionRateMatrix(q_FM) * vdot.template head<3>() -
496+
w_squared_over_four * Vector4<T>(q_FM.w(), q_FM.x(), q_FM.y(), q_FM.z());
497+
498+
// Calculate the 2nd-derivtive of the position vector p_FoMo_F = [x, y, z]ᵀ.
499+
// [ẍ, ÿ, z̈]ᵀ = [v̇x, v̇y, v̇z]ᵀ.
500+
qddot->template tail<3>() = vdot.template tail<3>();
501+
}
502+
488503
template <typename T>
489504
std::pair<Eigen::Quaternion<T>, Vector3<T>>
490505
QuaternionFloatingMobilizer<T>::GetPosePair(

multibody/tree/quaternion_floating_mobilizer.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,16 @@ class QuaternionFloatingMobilizer final : public MobilizerImpl<T, 7, 6> {
313313
const Eigen::Ref<const VectorX<T>>& qdot,
314314
EigenPtr<VectorX<T>> v) const final;
315315

316+
void DoMapAccelerationToQDDot(const systems::Context<T>& context,
317+
const Eigen::Ref<const VectorX<T>>& vdot,
318+
EigenPtr<VectorX<T>> qddot) const final;
319+
#if 0
320+
// Maps qddot to vdot by calculating v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈.
321+
void DoMapQDDotToAcceleration(const systems::Context<T>& context,
322+
const Eigen::Ref<const VectorX<T>>& qddot,
323+
EigenPtr<VectorX<T>> vdot) const final;
324+
#endif
325+
316326
std::unique_ptr<Mobilizer<double>> DoCloneToScalar(
317327
const MultibodyTree<double>& tree_clone) const final;
318328

@@ -325,12 +335,23 @@ class QuaternionFloatingMobilizer final : public MobilizerImpl<T, 7, 6> {
325335
private:
326336
// Helper to compute the kinematic map N(q). L ∈ ℝ⁴ˣ³.
327337
static Eigen::Matrix<T, 4, 3> CalcLMatrix(const Quaternion<T>& q);
328-
// Helper to compute the kinematic map N(q) from angular velocity to
329-
// quaternion time derivative for which q̇_WB = N(q)⋅w_WB.
330-
// With L given by CalcLMatrix we have:
331-
// N(q) = L(q_FM/2)
338+
339+
// Returns the 4x3 Nᵣ(q) matrix that relates q̇_FM = Nᵣ(q) * w_FM_F, where
340+
// q̇_FM = [q̇w, q̇x, q̇y, q̇z]ᵀ (time-derivative of quaternion for frames F and M)
341+
// w_FM_F = [ωx, ωy, ωz]ᵀ (frame M's angular velocity in F, expressed in F).
342+
//
343+
// ⌈ q̇w ⌉ ⌈ -qx -qy -qz ⌉ ⌈ ωx ⌉
344+
// | q̇x | = 0.5 | qw qz -qy | | ωy |
345+
// | q̇y | | -qz qw qx | ⌊ ωz ⌋
346+
// ⌊ q̇z ⌋ ⌊ qy -qx qw ⌋
347+
//
348+
// Herein L(q_FM) is the 4x3 matrix shown above, so Nᵣ(q) = 0.5 * L(q_FM).
349+
// Due to the linear nature of L(q_FM), 0.5 * L(q_FM) = L(0.5 * q_FM).
332350
static Eigen::Matrix<T, 4, 3> AngularVelocityToQuaternionRateMatrix(
333-
const Quaternion<T>& q);
351+
const Quaternion<T>& q_FM) {
352+
return CalcLMatrix(
353+
{0.5 * q_FM.w(), 0.5 * q_FM.x(), 0.5 * q_FM.y(), 0.5 * q_FM.z()});
354+
}
334355

335356
// Helper to compute the kinematic map N⁺(q) from quaternion time derivative
336357
// to angular velocity for which w_WB = N⁺(q)⋅q̇_WB.

0 commit comments

Comments
 (0)