Skip to content

Commit c507156

Browse files
author
Paul Mitiguy
committed
Create MapQDDotToAcceleration() for RPY ball mobilizer.
1 parent f3c36f7 commit c507156

File tree

3 files changed

+77
-1
lines changed

3 files changed

+77
-1
lines changed

multibody/tree/rpy_ball_mobilizer.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,66 @@ void RpyBallMobilizer<T>::MapQDotToVelocity(
368368
-sp * rdot /*+ 0 * pdot */ + ydot);
369369
}
370370

371+
template <typename T>
372+
void RpyBallMobilizer<T>::MapQDDotToAcceleration(
373+
const systems::Context<T>& context,
374+
const Eigen::Ref<const VectorX<T>>& qddot,
375+
EigenPtr<VectorX<T>> vdot) const {
376+
DRAKE_ASSERT(qddot.size() == kNq);
377+
DRAKE_ASSERT(vdot != nullptr);
378+
DRAKE_ASSERT(vdot->size() == kNv);
379+
380+
// Shown in MapQDotToVelocity(), the generalized velocities v = [ωx, ωy, ωz]ᵀ
381+
// are linearly related to q̇ = [ṙ, ṗ, ẏ]ᵀ (the time-derivatives of generalized
382+
// positions) as
383+
//
384+
// ⌈ ωx ⌉ ⌈cos(y) cos(p) -sin(y) 0⌉ ⌈ ṙ ⌉
385+
// | ωy | = |sin(y) cos(p) cos(y) 0| | ṗ |
386+
// ⌊ ωz ⌋ ⌊ -sin(p) 0 1⌋ ⌊ ẏ ⌋
387+
//
388+
// where, for this mobilizer, the angular velocity of the "fixed frame" F in
389+
// the "mobilized frame" M, expressed in frame F is w_FM_F = [ωx, ωy, ωz]ᵀ
390+
// and r, p, y denote roll, pitch, yaw angles.
391+
//
392+
// There are various ways to calculate v̇ = [ω̇x, ω̇y, ω̇z]ᵀ (the time-derivatives
393+
// of the generalized velocities). One efficient calculation uses
394+
//
395+
// ⌈ ω̇x ⌉ ⌈ cos(y) cos(p) -sin(y) 0 ⌉ ⌈ r̈ ⌉ ⌈-ωy ẏ - sin(p) cos(y) ṙ ṗ ⌉
396+
// | ω̇y | = | sin(y) cos(p) cos(y) 0 | | p̈ | + | wx ẏ - sin(p) sin(y) ṙ ṗ |
397+
// ⌊ ω̇z ⌋ ⌊ -sin(p) 0 1 ⌋ ⌊ ÿ ⌋ ⌊ -cos(p) ṙ ṗ ⌋
398+
399+
const T& rddot = qddot[0];
400+
const T& pddot = qddot[1];
401+
const T& yddot = qddot[2];
402+
403+
using std::cos;
404+
using std::sin;
405+
const Vector3<T> angles = get_angles(context);
406+
const T sp = sin(angles[1]);
407+
const T cp = cos(angles[1]);
408+
const T sy = sin(angles[2]);
409+
const T cy = cos(angles[2]);
410+
const T cp_x_rddot = cp * rddot;
411+
412+
// Compute the product w_FM = E_W * q̇ directly since it's cheaper than
413+
// explicitly forming E_F and then multiplying with q̇.
414+
*vdot = Vector3<T>(cy * cp_x_rddot - sy * pddot, /* + 0 * yddot */
415+
sy * cp_x_rddot + cy * pddot, /* + 0 * yddot */
416+
-sp * rddot /* + 0 * pddot */ + yddot);
417+
418+
const Vector3<T> v = get_angular_velocity(context);
419+
const T& wx = v[0];
420+
const T& wy = v[1];
421+
const T& wz = v[2];
422+
// const T rdot = (wx*cy + wy*sy) / cp;
423+
const T pdot = wy * cy - wx * sy;
424+
const T ydot = wz + sp / cp * (wx * cy + wy * sy);
425+
const T pdot_ydot = pdot * ydot;
426+
Vector3<T> alfExtra(-wy * ydot - sp * cy * pdot_ydot,
427+
wx * ydot - sp * sy * pdot_ydot, -cp * pdot_ydot);
428+
*vdot += alfExtra;
429+
}
430+
371431
template <typename T>
372432
template <typename ToScalar>
373433
std::unique_ptr<Mobilizer<ToScalar>>

multibody/tree/rpy_ball_mobilizer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,11 @@ class RpyBallMobilizer final : public MobilizerImpl<T, 3, 3> {
274274
const Eigen::Ref<const VectorX<T>>& qdot,
275275
EigenPtr<VectorX<T>> v) const override;
276276

277+
// Maps qddot to vdot, which for this mobilizer is complicated.
278+
void MapQDDotToAcceleration(const systems::Context<T>& context,
279+
const Eigen::Ref<const VectorX<T>>& qddot,
280+
EigenPtr<VectorX<T>> vdot) const final;
281+
277282
protected:
278283
void DoCalcNMatrix(const systems::Context<T>& context,
279284
EigenPtr<MatrixX<T>> N) const final;

multibody/tree/test/rpy_ball_mobilizer_test.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ TEST_F(RpyBallMobilizerTest, MapUsesNplus) {
129129
const Vector3d rpy_value(M_PI / 3, -M_PI / 3, M_PI / 5);
130130
mobilizer_->SetAngles(context_.get(), rpy_value);
131131

132-
// Set arbitrary qdot and MapQDotToVelocity.
132+
// Set arbitrary qdot and call MapQDotToVelocity().
133133
const Vector3<double> qdot = (Vector3<double>() << 1, 2, 3).finished();
134134
Vector3<double> v;
135135
mobilizer_->MapQDotToVelocity(*context_, qdot, &v);
@@ -141,6 +141,17 @@ TEST_F(RpyBallMobilizerTest, MapUsesNplus) {
141141
// Ensure N⁺(q) is used in v = N⁺(q)⋅q̇
142142
EXPECT_TRUE(CompareMatrices(v, Nplus * qdot, kTolerance,
143143
MatrixCompareType::relative));
144+
145+
// Ensure MapQDDotToAcceleration() works properly.
146+
const Vector3<double> qddot(1.2, 2.3, 3.4); // Set arbitrary values.
147+
Vector3<double> vdot;
148+
mobilizer_->MapQDDotToAcceleration(*context_, qdot, &v);
149+
150+
// Calculate vdot another way.
151+
// TODO(Mitiguy) Finish -- as of now this is a dumb test.
152+
Vector3<double> vdot_expected = Nplus * qddot; // NOT TRUE YET.
153+
EXPECT_FALSE(CompareMatrices(vdot, vdot_expected, kTolerance,
154+
MatrixCompareType::relative));
144155
}
145156

146157
TEST_F(RpyBallMobilizerTest, SingularityError) {

0 commit comments

Comments
 (0)