@@ -119,6 +119,41 @@ void BodyNodeImpl<T, ConcreteMobilizer>::CalcPositionKinematicsCache_BaseToTip(
119
119
p_PoBo_W = R_WP * p_PoBo_P;
120
120
}
121
121
122
+ // Calculate and save X_FM, X_MpM, X_WM
123
+ template <typename T, class ConcreteMobilizer >
124
+ void BodyNodeImpl<T, ConcreteMobilizer>::
125
+ CalcPositionKinematicsCacheInM_BaseToTip (
126
+ const FrameBodyPoseCache<T>& frame_body_pose_cache, const T* positions,
127
+ PositionKinematicsCacheInM<T>* pcm) const {
128
+ DRAKE_ASSERT (pcm != nullptr );
129
+ const MobodIndex index = mobod_index ();
130
+ DRAKE_ASSERT (index != world_mobod_index ());
131
+
132
+ const T* q = get_q (positions);
133
+
134
+ // Calculate and store X_FM.
135
+ math::RigidTransform<T>& X_FM = pcm->get_mutable_X_FM (mobod_index ());
136
+ X_FM = mobilizer_->calc_X_FM (q);
137
+
138
+ // Get precalculated frame info.
139
+ // This mobilizer's inboard frame, fixed on inboard (parent) body.
140
+ const FrameIndex index_F = inboard_frame ().index ();
141
+ const bool X_MpF_is_identity =
142
+ frame_body_pose_cache.is_X_MbF_identity (index_F);
143
+ const math::RigidTransform<T>& X_MpF =
144
+ frame_body_pose_cache.get_X_MbF (index_F);
145
+
146
+ // Calculate and store X_MpM.
147
+ math::RigidTransform<T>& X_MpM = pcm->get_mutable_X_MpM (mobod_index ());
148
+ X_MpM = X_MpF_is_identity ? X_FM : X_MpF * X_FM; // 0 or 63 flops
149
+
150
+ // Calculate and store X_WM.
151
+ // Inboard's M frame (Mp) pose is known since we're going base to tip.
152
+ const math::RigidTransform<T>& X_WMp = pcm->get_X_WM (inboard_mobod_index ());
153
+ math::RigidTransform<T>& X_WM = pcm->get_mutable_X_WM (mobod_index ());
154
+ X_WM = X_WMp * X_MpM; // 63 flops
155
+ }
156
+
122
157
// TODO(sherm1) Consider combining this with VelocityCache computation
123
158
// so that we don't have to make a separate pass. Or better, get rid of this
124
159
// computation altogether by working in better frames.
@@ -282,6 +317,43 @@ void BodyNodeImpl<T, ConcreteMobilizer>::CalcVelocityKinematicsCache_BaseToTip(
282
317
get_mutable_V_WB (vc) = V_WP.ComposeWithMovingFrameVelocity (p_PB_W, V_PB_W);
283
318
}
284
319
320
+ // Calculate V_FM_M and V_WM_M.
321
+ template <typename T, class ConcreteMobilizer >
322
+ void BodyNodeImpl<T, ConcreteMobilizer>::
323
+ CalcVelocityKinematicsCacheInM_BaseToTip (
324
+ const T* positions, const PositionKinematicsCacheInM<T>& pcm,
325
+ const T* velocities, VelocityKinematicsCacheInM<T>* vcm) const {
326
+ DRAKE_ASSERT (vcm != nullptr );
327
+ const MobodIndex index = mobod_index ();
328
+ DRAKE_ASSERT (index != world_mobod_index ());
329
+
330
+ // Generalized coordinates local to this node's mobilizer.
331
+ const T* q = get_q (positions);
332
+ const T* v = get_v (velocities);
333
+
334
+ const math::RigidTransform<T>& X_FM = pcm.get_X_FM (index);
335
+
336
+ SpatialVelocity<T>& V_FM_M = vcm->get_mutable_V_FM_M (index);
337
+ V_FM_M = mobilizer_->calc_V_FM_M (X_FM, q, v); // 3 flops: revolute/prismatic
338
+ // 30 flops: floating
339
+
340
+ const math::RigidTransform<T>& X_MpM = pcm.get_X_MpM (index);
341
+ const Vector3<T>& p_MpM_Mp = X_MpM.translation (); // Shift vector
342
+ const math::RotationMatrix<T> R_MMp = X_MpM.rotation ().inverse ();
343
+
344
+ // We're going base to tip so we know the inboard body's M-frame velocity.
345
+ const SpatialVelocity<T>& V_WMp_Mp = vcm->get_V_WM_M (inboard_mobod_index ());
346
+
347
+ // Let Mc be a frame fixed to parent body P but coincident with the child
348
+ // body's M frame. Then this is the spatial velocity of P, shifted to Mc,
349
+ // but expressed in the Mp frame.
350
+ const SpatialVelocity<T> V_WMc_Mp = V_WMp_Mp.Shift (p_MpM_Mp); // 15 flops
351
+
352
+ SpatialVelocity<T>& V_WM_M = vcm->get_mutable_V_WM_M (index);
353
+ V_WM_M = R_MMp * V_WMc_Mp // 6 SIMD flops
354
+ + V_FM_M; // 6 flops
355
+ }
356
+
285
357
// As a guideline for developers, a summary of the computations performed in
286
358
// this method is provided:
287
359
// Notation:
@@ -411,6 +483,60 @@ void BodyNodeImpl<T, ConcreteMobilizer>::CalcSpatialAcceleration_BaseToTip(
411
483
V_PB_W, A_PB_W);
412
484
}
413
485
486
+ template <typename T, class ConcreteMobilizer >
487
+ void BodyNodeImpl<T, ConcreteMobilizer>::CalcSpatialAccelerationInM_BaseToTip(
488
+ const T* positions, const PositionKinematicsCacheInM<T>& pcm,
489
+ const T* velocities, const VelocityKinematicsCacheInM<T>& vcm,
490
+ const T* accelerations,
491
+ std::vector<SpatialAcceleration<T>>* A_WM_M_array) const {
492
+ const MobodIndex index = mobod_index (); // mobod B
493
+
494
+ // Collect the inputs.
495
+ const math::RigidTransform<T>& X_MpM = pcm.get_X_MpM (index);
496
+ const SpatialVelocity<T>& V_WM_M = vcm.get_V_WM_M (index);
497
+ const T* q = get_q (positions);
498
+ const T* v = get_v (velocities);
499
+ const T* vdot = get_v (accelerations);
500
+ // Inboard (parent) body's M frame spatial velocity and spatial acceleration
501
+ // in World (already computed in base-to-tip ordering).
502
+ const SpatialVelocity<T>& V_WMp_Mp = vcm.get_V_WM_M (inboard_mobod_index ());
503
+ const SpatialAcceleration<T>& A_WMp_Mp =
504
+ (*A_WM_M_array)[inboard_mobod_index ()];
505
+
506
+ // This is going to be the output.
507
+ SpatialAcceleration<T>& A_WM_M = (*A_WM_M_array)[index];
508
+
509
+ // Shift and re-express parent contribution.
510
+ const Vector3<T>& p_MpM_Mp = X_MpM.translation ();
511
+ const math::RotationMatrix<T> R_MMp = X_MpM.rotation ().inverse ();
512
+ const Vector3<T>& w_WP_Mp = V_WMp_Mp.rotational (); // all frames on P same ω
513
+
514
+ // Start with parent contribution. shift: 33 flops, reexpress: 6 SIMD flops
515
+ A_WM_M = R_MMp * A_WMp_Mp.Shift (p_MpM_Mp, w_WP_Mp); // parent contribution
516
+
517
+ // Next add in the velocity-dependent bias acceleration:
518
+ // Ab_M = ω_WP x ω_FM note: ω_WF == ω_WP
519
+ // 2 * ω_WP x v_FM
520
+ const SpatialVelocity<T>& V_FM_M = vcm.get_V_FM_M (index);
521
+ const Vector3<T>& w_FM_M = V_FM_M.rotational ();
522
+ const Vector3<T>& v_FM_M = V_FM_M.translational ();
523
+ const Vector3<T>& w_WM_M = V_WM_M.rotational ();
524
+
525
+ // To avoid re-expressing w_WP_Mp in M, we can use this identity:
526
+ // w_WM = w_WP + w_FM, so w_WP = w_WM - w_FM.
527
+ const Vector3<T> w_WP_M = w_WM_M - w_FM_M; // 3 flops
528
+ const SpatialAcceleration<T> Ab_WM_M (w_WP_M.cross (w_FM_M), // 12 flops
529
+ 2 * w_WP_M.cross (v_FM_M)); // 15 flops
530
+ A_WM_M += Ab_WM_M; // 6 flops
531
+
532
+ // Calculate cross-mobilizer spatial acceleration.
533
+ const math::RigidTransform<T>& X_FM = pcm.get_X_FM (index);
534
+ const SpatialAcceleration<T> A_FM_M =
535
+ mobilizer_->calc_A_FM_M (X_FM, q, v, vdot); // 3 flops revolute/prismatic
536
+ // 30 flops floating
537
+ A_WM_M += A_FM_M; // 6 flops
538
+ }
539
+
414
540
// As a guideline for developers, a summary of the computations performed in
415
541
// this method is provided:
416
542
// Notation:
@@ -586,6 +712,79 @@ void BodyNodeImpl<T, ConcreteMobilizer>::CalcInverseDynamics_TipToBase(
586
712
}
587
713
}
588
714
715
+ template <typename T, class ConcreteMobilizer >
716
+ void BodyNodeImpl<T, ConcreteMobilizer>::CalcInverseDynamicsInM_TipToBase(
717
+ const FrameBodyPoseCache<T>& frame_body_pose_cache, // M_BMo_M, X_BM
718
+ const T* positions,
719
+ const PositionKinematicsCacheInM<T>& pcm, // X_MpM, X_WM
720
+ const VelocityKinematicsCacheInM<T>& vcm, // V_WM_M
721
+ const std::vector<SpatialAcceleration<T>>& A_WM_M_array,
722
+ const std::vector<SpatialForce<T>>& Fapplied_Bo_W_array, // Bo, W !
723
+ const Eigen::Ref<const VectorX<T>>& tau_applied_array,
724
+ std::vector<SpatialForce<T>>* F_BMo_M_array,
725
+ EigenPtr<VectorX<T>> tau_array) const {
726
+ const MobodIndex index = mobod_index (); // mobod B
727
+
728
+ // Model parameters: mass properties, frame locations.
729
+ const SpatialInertia<T>& M_BMo_M = frame_body_pose_cache.get_M_BMo_M (index);
730
+ const T& mass = M_BMo_M.get_mass ();
731
+ const Vector3<T>& p_MoBcm_M = M_BMo_M.get_com ();
732
+ const UnitInertia<T>& G_BMo_M = M_BMo_M.get_unit_inertia ();
733
+
734
+ const math::RigidTransform<T>& X_MB =
735
+ outboard_frame ().get_X_FB (frame_body_pose_cache); // F==M
736
+ const Vector3<T>& p_MoBo_M = X_MB.translation ();
737
+
738
+ // Kinematics.
739
+ const math::RotationMatrix<T> R_MW = pcm.get_X_WM (index).rotation ().inverse ();
740
+ const SpatialVelocity<T>& V_WM_M = vcm.get_V_WM_M (index);
741
+ const Vector3<T>& w_WM_M = V_WM_M.rotational ();
742
+ const SpatialAcceleration<T>& A_WM_M = A_WM_M_array[index];
743
+
744
+ // Unfortunately the applied force is given at Bo and expressed in W. We
745
+ // need it applied at Mo and expressed in M.
746
+ const SpatialForce<T>& Fapp_BBo_W = Fapplied_Bo_W_array[index];
747
+ const SpatialForce<T> Fapp_BBo_M = R_MW * Fapp_BBo_W; // 6 SIMD flops
748
+ const SpatialForce<T> Fapp_BMo_M = Fapp_BBo_M.Shift (-p_MoBo_M); // 15 flops
749
+
750
+ // Calculate the velocity-dependent bias force on B (48 flops).
751
+ const SpatialForce<T> Fbias_BMo_M (
752
+ mass * w_WM_M.cross (G_BMo_M * w_WM_M), // bias moment, 27 flops
753
+ mass * w_WM_M.cross (w_WM_M.cross (p_MoBcm_M))); // bias force, 21 flops
754
+
755
+ // F_BMo_M is an output and will be the total force on B.
756
+ SpatialForce<T>& F_BMo_M = (*F_BMo_M_array)[index];
757
+ F_BMo_M = M_BMo_M * A_WM_M // 45 flops
758
+ + Fbias_BMo_M - Fapp_BMo_M; // 12 flops
759
+
760
+ // Next, account for forces applied to B through its outboard joints, treated
761
+ // as though they were locked. Since we're going tip to base we already have
762
+ // the total force F_CMc_Mc on each outboard body C. 51 flops per
763
+ for (const BodyNode<T>* outboard_node : child_nodes ()) {
764
+ const MobodIndex outboard_index = outboard_node->mobod_index ();
765
+
766
+ // Outboard body's kinematics.
767
+ const math::RigidTransform<T>& X_MMc = pcm.get_X_MpM (outboard_index);
768
+ const math::RotationMatrix<T>& R_MMc = X_MMc.rotation ();
769
+ const Vector3<T>& p_MoMc_M = X_MMc.translation ();
770
+
771
+ const SpatialForce<T>& F_CMc_Mc = (*F_BMo_M_array)[outboard_index];
772
+ const SpatialForce<T> F_CMc_M = R_MMc * F_CMc_Mc; // 6 SIMD flops
773
+ const SpatialForce<T> F_CMo_M = F_CMc_M.Shift (-p_MoMc_M); // 15 flops
774
+ F_BMo_M += F_CMo_M; // 6 flops
775
+ }
776
+
777
+ // tau is the primary output.
778
+ Eigen::Map<VVector<T>> tau (get_mutable_v (tau_array->data ()));
779
+ const Eigen::Map<const VVector<T>> tau_app (get_v (tau_applied_array.data ()));
780
+ VVector<T> tau_projection; // = Hᵀ_FM_M ⋅ F_BMo_M
781
+ const math::RigidTransform<T>& X_FM = pcm.get_X_FM (index);
782
+ // Next line is 5 flops for revolute/prismatic, 30 flops for floating
783
+ mobilizer_->calc_tau_from_M (X_FM, get_q (positions), F_BMo_M,
784
+ tau_projection.data ());
785
+ tau = tau_projection - tau_app; // 1-6 flops
786
+ }
787
+
589
788
template <typename T, class ConcreteMobilizer >
590
789
void BodyNodeImpl<T, ConcreteMobilizer>::
591
790
CalcArticulatedBodyInertiaCache_TipToBase (
0 commit comments