25
25
#include " drake/multibody/plant/hydroelastic_traction_calculator.h"
26
26
#include " drake/multibody/plant/make_discrete_update_manager.h"
27
27
#include " drake/multibody/plant/slicing_and_indexing.h"
28
+ #include " drake/multibody/topology/spanning_forest_model.h"
28
29
#include " drake/multibody/tree/prismatic_joint.h"
29
30
#include " drake/multibody/tree/quaternion_floating_joint.h"
30
31
#include " drake/multibody/tree/revolute_joint.h"
@@ -328,7 +329,6 @@ MultibodyPlant<T>::MultibodyPlant(
328
329
// it less brittle.
329
330
visual_geometries_.emplace_back (); // Entries for the "world" body.
330
331
collision_geometries_.emplace_back ();
331
-
332
332
DeclareSceneGraphPorts ();
333
333
}
334
334
@@ -889,7 +889,7 @@ template <typename T>
889
889
std::vector<const Body<T>*> MultibodyPlant<T>::GetBodiesWeldedTo(
890
890
const Body<T>& body) const {
891
891
const std::set<BodyIndex> island =
892
- internal_tree ().multibody_graph ().FindBodiesWeldedTo (body.index ());
892
+ internal_tree ().link_joint_graph ().FindLinksWeldedTo (body.index ());
893
893
// Map body indices to pointers.
894
894
std::vector<const Body<T>*> sub_graph_bodies;
895
895
for (BodyIndex body_index : island) {
@@ -1097,8 +1097,61 @@ void MultibodyPlant<T>::RenameModelInstance(ModelInstanceIndex model_instance,
1097
1097
1098
1098
template <typename T>
1099
1099
void MultibodyPlant<T>::Finalize() {
1100
- // After finalizing the base class, tree is read-only.
1101
- internal::MultibodyTreeSystem<T>::Finalize ();
1100
+ /* Given the user-defined directed graph of Links and Joints, decide how we're
1101
+ going to model this using a spanning forest comprised of
1102
+ - bodies and their mobilizers, paired as "mobilized bodies" (mobods) and
1103
+ directed by inboard/outboard edges, and
1104
+ - added constraints where needed to close kinematic loops in the graph.
1105
+ The modeler sorts the mobilized bodies into depth-first order.
1106
+
1107
+ Every Link will be modeled with one "primary" body and possibly several
1108
+ "shadow" bodies. Every Joint will be modeled with a mobilizer, with the
1109
+ Joint's parent/child connections mapped to the mobilizer's inboard/outboard
1110
+ connection or to the reverse, as necessary for the mobilizers to form a
1111
+ properly-directed tree. Every body in the tree must have a path in the
1112
+ inboard direction connecting it to World. If necessary, additional "floating"
1113
+ (6 dof) or "weld" (0 dof) mobilizers are added to make the final connection
1114
+ to World.
1115
+
1116
+ During the modeling process, the LinkJointGraph is augmented to have
1117
+ additional elements to provide an interface to the additional elements that
1118
+ were required to build the model. Below, we will augment the MultibodyPlant
1119
+ elements to match, so that advanced users can use the familiar Plant API to
1120
+ access and control these elements. */
1121
+ this ->mutable_tree ().BuildSpanningForest ();
1122
+
1123
+ /* Add Links, Joints, and Constraints that were created during the modeling
1124
+ process. */
1125
+
1126
+ const internal::LinkJointGraph& graph = internal_tree ().link_joint_graph ();
1127
+ unused (graph);
1128
+
1129
+ /* TODO(sherm1) why not use MbP as the LinkJointGraph and do away with
1130
+ the extra class? Then we wouldn't have to repeat these additions.
1131
+ // Added floating mobods are in the order the new joints were added so
1132
+ // the index we get in the plant should match the one stored with the mobod.
1133
+ for (auto index : graph.added_floating_mobods()) {
1134
+ const internal::SpanningForestModel::Mobod& floating_mobod =
1135
+ model.mobods()[index];
1136
+ const JointIndex floating = AddFloatingJointToWorld(floating_mobod);
1137
+ DRAKE_DEMAND(floating == floating_mobod.joint_index);
1138
+ }
1139
+
1140
+ // Shadow mobods are in the order the new bodies were added so the body
1141
+ // index should match.
1142
+ for (auto index : model.shadow_mobods()) {
1143
+ const internal::SpanningForestModel::Mobod shadow_mobod = model.mobods()[index];
1144
+ const BodyIndex shadow = AddShadowBody(shadow_mobod);
1145
+ DRAKE_DEMAND(shadow == shadow_mobod.link_index_);
1146
+ }
1147
+
1148
+ // The modeler only knows about constraints it adds so there is no
1149
+ // indexing correspondence.
1150
+ for (auto& loop_constraint : model.added_constraints()) {
1151
+ const ConstraintIndex constraint =
1152
+ AddLoopClosingConstraint(loop_constraint);
1153
+ }
1154
+ */
1102
1155
1103
1156
if (geometry_source_is_registered ()) {
1104
1157
ApplyDefaultCollisionFilters ();
@@ -1120,6 +1173,12 @@ void MultibodyPlant<T>::Finalize() {
1120
1173
" only supported for discrete models. Refer to MultibodyPlant's "
1121
1174
" documentation for further details." );
1122
1175
}
1176
+
1177
+ /* The Plant is complete now. Next, build an efficient computational
1178
+ representation structured in accordance with `model`. */
1179
+
1180
+ // After finalizing the base class, tree is read-only.
1181
+ internal::MultibodyTreeSystem<T>::Finalize ();
1123
1182
}
1124
1183
1125
1184
template <typename T>
@@ -1342,7 +1401,7 @@ void MultibodyPlant<T>::ApplyDefaultCollisionFilters() {
1342
1401
}
1343
1402
// We explicitly exclude collisions within welded subgraphs.
1344
1403
std::vector<std::set<BodyIndex>> subgraphs =
1345
- internal_tree ().multibody_graph ().FindSubgraphsOfWeldedBodies ();
1404
+ internal_tree ().link_joint_graph ().FindSubgraphsOfWeldedLinks ();
1346
1405
for (const auto & subgraph : subgraphs) {
1347
1406
// Only operate on non-trivial weld subgraphs.
1348
1407
if (subgraph.size () <= 1 ) { continue ; }
@@ -3558,7 +3617,7 @@ void MultibodyPlant<T>::RemoveUnsupportedScalars(
3558
3617
template <typename T>
3559
3618
std::vector<std::set<BodyIndex>>
3560
3619
MultibodyPlant<T>::FindSubgraphsOfWeldedBodies() const {
3561
- return internal_tree ().multibody_graph ().FindSubgraphsOfWeldedBodies ();
3620
+ return internal_tree ().link_joint_graph ().FindSubgraphsOfWeldedLinks ();
3562
3621
}
3563
3622
3564
3623
template <typename T>
0 commit comments