Skip to content

Commit 7835a40

Browse files
author
Paul Mitiguy
committed
Respond to Alejandro's comments.
1 parent 6cbb397 commit 7835a40

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

multibody/tree/rpy_ball_mobilizer.cc

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
namespace drake {
1515
namespace multibody {
1616
namespace internal {
17+
// The following tolerance is used to test whether the cosine of the pitch angle
18+
// is near zero, which occurs when the pitch angle ≈ π/2 ± n π (n=0, 1 2, …).
19+
// An exception is thrown if a pitch angle is within ≈ 0.057° of a singularity.
20+
constexpr double kToleranceCosPitchNearZero = 1.0e-3;
1721

1822
template <typename T>
1923
RpyBallMobilizer<T>::~RpyBallMobilizer() = default;
@@ -164,7 +168,7 @@ void RpyBallMobilizer<T>::DoCalcNMatrix(const systems::Context<T>& context,
164168
using std::sin;
165169
const Vector3<T> angles = get_angles(context);
166170
const T cp = cos(angles[1]);
167-
if (abs(cp) < 1.0e-3) {
171+
if (abs(cp) < kToleranceCosPitchNearZero) {
168172
const char* function_name_less_Do = __func__ + 2;
169173
ThrowSinceCosPitchIsNearZero(angles[1], function_name_less_Do);
170174
}
@@ -239,7 +243,7 @@ void RpyBallMobilizer<T>::DoCalcNDotMatrix(const systems::Context<T>& context,
239243
const T sp = sin(angles[1]);
240244
const T sy = sin(angles[2]);
241245
const T cy = cos(angles[2]);
242-
if (abs(cp) < 1.0e-3) {
246+
if (abs(cp) < kToleranceCosPitchNearZero) {
243247
const char* function_name_less_Do = __func__ + 2;
244248
ThrowSinceCosPitchIsNearZero(angles[1], function_name_less_Do);
245249
}
@@ -298,7 +302,7 @@ void RpyBallMobilizer<T>::DoCalcNplusDotMatrix(
298302

299303
// Throw an exception with the proper function name if a singularity would be
300304
// encountered in DoMapVelocityToQDot().
301-
if (abs(cp) < 1.0e-3) {
305+
if (abs(cp) < kToleranceCosPitchNearZero) {
302306
const char* function_name_less_Do = __func__ + 2;
303307
ThrowSinceCosPitchIsNearZero(angles[1], function_name_less_Do);
304308
}
@@ -361,7 +365,7 @@ void RpyBallMobilizer<T>::DoMapVelocityToQDot(
361365
const T cp = cos(angles[1]);
362366
const T sy = sin(angles[2]);
363367
const T cy = cos(angles[2]);
364-
if (abs(cp) < 1.0e-3) {
368+
if (abs(cp) < kToleranceCosPitchNearZero) {
365369
const char* function_name_less_Do = __func__ + 2;
366370
ThrowSinceCosPitchIsNearZero(angles[1], function_name_less_Do);
367371
}
@@ -456,13 +460,13 @@ Vector3<T> RpyBallMobilizer<T>::CalcAccelerationBiasForQDDot(
456460
const T sp = sin(angles[1]);
457461
const T sy = sin(angles[2]);
458462
const T cy = cos(angles[2]);
459-
if (abs(cp) < 1.0e-3) {
463+
if (abs(cp) < kToleranceCosPitchNearZero) {
460464
ThrowSinceCosPitchIsNearZero(angles[1], function_name);
461465
}
462-
// The algorithm below efficiently calculates Ṅ⁺(q,q̇)⋅q̇. The algorithm was
463-
// verified with MotionGenesis. It can also be verified by-hand, e.g., with
464-
// the documentation in DoCalcNplusDotMatrix which differentiates N⁺(q) to
465-
// form Ṅ⁺(q,q̇). Thereafter, multiply by q̇ to form Ṅ⁺(q,q̇)⋅q̇ (and simplify).
466+
// The algorithm below calculates Ṅ⁺(q,q̇)⋅q̇. The algorithm was verified with
467+
// MotionGenesis. It can also be verified by-hand, e.g., with documentation
468+
// in DoCalcNplusDotMatrix which directly differentiates N⁺(q) to form
469+
// Ṅ⁺(q,q̇). Thereafter, multiply by q̇ to form Ṅ⁺(q,q̇)⋅q̇ (and simplify).
466470
const Vector3<T> v = get_angular_velocity(context);
467471
Vector3<T> qdot;
468472
DoMapVelocityToQDot(context, v, &qdot);
@@ -484,7 +488,6 @@ void RpyBallMobilizer<T>::DoMapAccelerationToQDDot(
484488
const systems::Context<T>& context,
485489
const Eigen::Ref<const VectorX<T>>& vdot,
486490
EigenPtr<VectorX<T>> qddot) const {
487-
// --------------------------------------------------------------------------
488491
// As shown in DoMapVelocityToQDot(), the time-derivatives of generalized
489492
// positions q̇ = [ṙ, ṗ, ẏ]ᵀ are related to the generalized velocities
490493
// v = [ωx, ωy, ωz]ᵀ in the matrix form q̇ = N(q)⋅v, where N is a 3x3 matrix.
@@ -494,16 +497,16 @@ void RpyBallMobilizer<T>::DoMapAccelerationToQDDot(
494497
// q = [r, p, y]ᵀ denote roll, pitch, yaw angles (generalized positions).
495498
//
496499
// There are various ways to get q̈ = [r̈, p̈, ÿ]ᵀ in terms of v̇ = [ω̇x, ω̇y, ω̇z]ᵀ.
497-
// A simple calculation directly solves for q̈ as q̈ = Ṅ(q,q̇)⋅v + N(q)⋅v̇.
500+
// One way to is differentiate q̇ = N(q)⋅v to form q̈ = Ṅ(q,q̇)⋅v + N(q)⋅v̇.
498501
// However, N⁺(q) is simpler than N(q) so Ṅ⁺(q,q̇) is much simpler than Ṅ(q,q̇).
499-
// Hence, a more efficient calculation of q̈ starts as v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈
500-
// and then solves as q̈ = N(q) {v̇ - Ṅ⁺(q,q̇)⋅q̇}.
501-
// --------------------------------------------------------------------------
502+
// A calculation of q̈ that leverages the simplicity of Ṅ⁺(q,q̇) over Ṅ(q,q̇)
503+
// and the available function CalcAccelerationBiasForQDDot() starts with
504+
// v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈ and then solves as q̈ = N(q) {v̇ - Ṅ⁺(q,q̇)⋅q̇}.
502505
const Vector3<T> vdot_minus_NplusDotTimesQDot =
503506
vdot - CalcAccelerationBiasForQDDot(context, __func__);
504507

505-
// Note: Although the function below was designed to efficiently calculate
506-
// q̇ = N(q)⋅v, it can also be used to calculate q̈ = N(q) {v̇ - Ṅ⁺(q,q̇)⋅q̇}.
508+
// Note: Although the function below was designed to calculate q̇ = N(q)⋅v,
509+
// it can also be used to calculate q̈ = N(q) {v̇ - Ṅ⁺(q,q̇)⋅q̇}.
507510
DoMapVelocityToQDot(context, vdot_minus_NplusDotTimesQDot, qddot);
508511
}
509512

@@ -512,7 +515,6 @@ void RpyBallMobilizer<T>::DoMapQDDotToAcceleration(
512515
const systems::Context<T>& context,
513516
const Eigen::Ref<const VectorX<T>>& qddot,
514517
EigenPtr<VectorX<T>> vdot) const {
515-
// --------------------------------------------------------------------------
516518
// As seen in DoMapQDotToVelocity(), generalized velocities v = [ωx, ωy, ωz]ᵀ
517519
// are related to q̇ = [ṙ, ṗ, ẏ]ᵀ (time-derivatives of generalized positions)
518520
// in the matrix form v = N⁺(q)⋅q̇, where N⁺ is a 3x3 matrix.
@@ -524,7 +526,7 @@ void RpyBallMobilizer<T>::DoMapQDDotToAcceleration(
524526
// There are various ways to calculate v̇ = [ω̇x, ω̇y, ω̇z]ᵀ (the time-derivatives
525527
// of the generalized velocities). The calculation below is straighforward in
526528
// that it simply differentiates v = N⁺(q)⋅q̇ to form v̇ = Ṅ⁺(q,q̇)⋅q̇ + N⁺(q)⋅q̈.
527-
// --------------------------------------------------------------------------
529+
528530
// Form the Ṅ⁺(q,q̇)⋅q̇ term of the result now (start of this function) so any
529531
// singularity (if one exists) throws an exception referencing this function.
530532
const Vector3<T> NplusDot_times_Qdot =

0 commit comments

Comments
 (0)