@@ -228,6 +228,16 @@ enum class DiscreteContactApproximation {
228
228
kLagged ,
229
229
};
230
230
231
+ // / The kind of joint to be used to connect base bodies to world at Finalize().
232
+ // / See @ref mbp_working_with_free_bodies "Working with free bodies"
233
+ // / for definitions and discussion.
234
+ // / @see SetBaseBodyJointType() for details.
235
+ enum class BaseBodyJointType {
236
+ kQuaternionFloatingJoint , // /< 6 dofs, unrestricted orientation.
237
+ kRpyFloatingJoint , // /< 6 dofs using 3 angles; has singularity.
238
+ kWeldJoint , // /< 0 dofs, fixed to World.
239
+ };
240
+
231
241
// / @cond
232
242
// Helper macro to throw an exception within methods that should not be called
233
243
// post-finalize.
@@ -1667,6 +1677,53 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
1667
1677
void RenameModelInstance (ModelInstanceIndex model_instance,
1668
1678
const std::string& name);
1669
1679
1680
+ // / Sets the type of joint to be used by Finalize() to connect any otherwise
1681
+ // / unconnected bodies to World. Bodies connected by a joint to World are
1682
+ // / called _base bodies_ and are determined during Finalize() when we build
1683
+ // / a forest structure to model the multibody system for efficient
1684
+ // / computation.
1685
+ // / See @ref mbp_working_with_free_bodies "Working with free bodies"
1686
+ // / for a longer discussion.
1687
+ // /
1688
+ // / This can be set globally or for a particular model instance. Global
1689
+ // / options are used for any model elements that belong to model instances for
1690
+ // / which no options have been set explicitly. The default is to use a
1691
+ // / quaternion floating joint.
1692
+ // /
1693
+ // / | BaseBodyJointType:: | Notes |
1694
+ // / | ------------------------ | -------------------------------------- |
1695
+ // / | kQuaternionFloatingJoint | 6 dofs, unrestricted orientation |
1696
+ // / | kRpyFloatingJoint † | 6 dofs, uses 3 angles for orientation |
1697
+ // / | kWeldJoint | 0 dofs, welded to World ("anchored") |
1698
+ // /
1699
+ // / † The 3-angle orientation representation used by RpyFloatingJoint can be
1700
+ // / easier to work with than a quaternion (especially for optimization) but
1701
+ // / has a singular orientation which must be avoided (pitch angle near 90°).
1702
+ // /
1703
+ // / @note Reminder: if you aren't satisfied with the particular selection of
1704
+ // / joints here, you can always add an explicit joint to World with
1705
+ // / AddJoint().
1706
+ // /
1707
+ // / @param[in] joint_type The joint type to be used for base bodies.
1708
+ // / @param[in] model_instance (optional) the index of the model instance to
1709
+ // / which `joint_type` is to be applied.
1710
+ // / @throws std::exception if called after Finalize().
1711
+ void SetBaseBodyJointType (
1712
+ BaseBodyJointType joint_type,
1713
+ std::optional<ModelInstanceIndex> model_instance = {});
1714
+
1715
+ // / Returns the currently-set choice for base body joint type, either for
1716
+ // / the global setting or for a specific model instance if provided.
1717
+ // / If a model instance is provided for which no explicit choice has been
1718
+ // / made, the global setting is returned. Any model instance index is
1719
+ // / acceptable here; if not recognized then the global setting is returned.
1720
+ // / This can be called any time -- pre-finalize it returns the joint type
1721
+ // / that will be used by Finalize(); post-finalize it returns the joint type
1722
+ // / that _was_ used if there were any base bodies in need of a joint.
1723
+ // / @see SetBaseBodyJointType()
1724
+ BaseBodyJointType GetBaseBodyJointType (
1725
+ std::optional<ModelInstanceIndex> model_instance = {}) const ;
1726
+
1670
1727
// / This method must be called after all elements in the model (joints,
1671
1728
// / bodies, force elements, constraints, etc.) are added and before any
1672
1729
// / computations are performed.
@@ -3101,22 +3158,26 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
3101
3158
// / A %MultibodyPlant user adds sets of RigidBody and Joint objects to `this`
3102
3159
// / plant to build a physical representation of a mechanical model.
3103
3160
// / At Finalize(), %MultibodyPlant builds a mathematical representation of
3104
- // / such system, consisting of a tree representation. In this
3105
- // / representation each body is assigned a Mobilizer, which grants a certain
3161
+ // / such system as a forest of trees, with each tree's root (which we call
3162
+ // / that tree's _base body_) connected directly to World by a joint defining
3163
+ // / the base body's mobility. If no input joint is provided for a base body,
3164
+ // / one is added automatically. The function SetBaseBodyJointType() can be
3165
+ // / used to change the type of joint used.
3166
+ // /
3167
+ // / In this representation each input Joint (including those added for base
3168
+ // / bodies) is modeled internally using a Mobilizer, which grants a certain
3106
3169
// / number of degrees of freedom in accordance to the physical specification.
3107
- // / In this regard, the modeling representation can be seen as a forest of
3108
- // / tree structures each of which contains a single body at the root of the
3109
- // / tree. The root body's parent is always the world body. If a body has _six_
3110
- // / degrees of freedom with respect to its parent, it is called a "free body".
3111
- // / If it also the root of a tree, such that its parent is the world body,
3112
- // / it is a "floating base" body. Free bodies that are added to the plant
3113
- // / without specifying a joint become floating base bodies after
3114
- // / finalization. It is possible (and sometimes recommended) to explicitly
3115
- // / create a 6-dof joint between two bodies. The child body would be free,
3116
- // / because it has six degrees of freedom, but it would _not_ be a "floating
3117
- // / base body" because its parent is not the world. The effects of the various
3118
- // / APIs below depend on the distinction between "free" and "floating base
3119
- // / bodies". Read carefully.
3170
+ // / If a body has _six_ degrees of freedom with respect to its parent, it is
3171
+ // / called a _free body_. If it also the root of a tree, such that its parent
3172
+ // / is the world body, it is a _floating base body_. Bodies that are added to
3173
+ // / the plant without specifying a joint normally become floating base bodies
3174
+ // / after finalization.
3175
+ // /
3176
+ // / It is possible (and sometimes recommended) to explicitly create a 6-dof
3177
+ // / joint between two bodies. The child body would be free, because it has six
3178
+ // / degrees of freedom, but it would _not_ be a floating base body because its
3179
+ // / parent is not the world. The effects of the various APIs below depend on
3180
+ // / the distinction between "free" and "floating base bodies". Read carefully.
3120
3181
// / A user can request the set of all floating base bodies with a call to
3121
3182
// / GetFloatingBaseBodies(). Alternatively, a user can query whether a
3122
3183
// / RigidBody is a floating base body or not with RigidBody::is_floating().
@@ -3128,8 +3189,8 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
3128
3189
// / _not_ 6-dof free bodies generally.
3129
3190
// /
3130
3191
// / It is sometimes convenient for users to perform operations on RigidBodies
3131
- // / uniformly through the APIs of the Joint class. For that reason the
3132
- // / plant implicitly constructs a 6-dof joint, QuaternionFloatingJoint,
3192
+ // / uniformly through the APIs of the Joint class. For that reason the plant
3193
+ // / implicitly constructs a 6-dof joint, typically a QuaternionFloatingJoint,
3133
3194
// / between the body and the world for all bodies otherwise without declared
3134
3195
// / inboard joints at the time of Finalize(). Using Joint APIs to affect a
3135
3196
// / free body (setting state, changing parameters, etc.) has the same effect
@@ -3262,11 +3323,24 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
3262
3323
}
3263
3324
3264
3325
// / Sets the distribution used by SetRandomState() to populate the free
3265
- // / body's `rotation` with respect to its parent frame.
3326
+ // / body's orientation with respect to its parent frame, expressed as a
3327
+ // / quaternion. Requires that the free body is modeled using a
3328
+ // / QuaternionFloatingJoint.
3266
3329
// / @note The parent frame is not necessarily the world frame. See
3267
- // / @ref mbp_working_with_free_bodies "above for details".
3330
+ // / @ref mbp_working_with_free_bodies "above for details".
3331
+ // / @note This distribution is not necessarily uniform over the sphere
3332
+ // / reachable by the quaternion; that depends on the quaternion expression
3333
+ // / provided in `rotation`. See
3334
+ // / SetFreeBodyRandomRotationDistributionToUniform() for a uniform
3335
+ // / alternative.
3268
3336
// / @throws std::exception if `body` is not a free body in the model.
3337
+ // / @throws std::exception if the free body is not modeled with a
3338
+ // / QuaternionFloatingJoint.
3269
3339
// / @throws std::exception if called pre-finalize.
3340
+ // / @see SetFreeBodyRandomAnglesDistribution() for a free body that is
3341
+ // / modeled using an RpyFloatingJoint.
3342
+ // / @see SetBaseBodyJointType() for control over the type of automatically-
3343
+ // / added joints.
3270
3344
void SetFreeBodyRandomRotationDistribution (
3271
3345
const RigidBody<T>& body,
3272
3346
const Eigen::Quaternion<symbolic::Expression>& rotation) {
@@ -3275,14 +3349,46 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
3275
3349
}
3276
3350
3277
3351
// / Sets the distribution used by SetRandomState() to populate the free
3278
- // / body's rotation with respect to its parent frame using uniformly random
3279
- // / rotations.
3352
+ // / body's orientation with respect to its parent frame using uniformly random
3353
+ // / rotations (expressed as a quaternion). Requires that the free body is
3354
+ // / modeled using a QuaternionFloatingJoint.
3280
3355
// / @note The parent frame is not necessarily the world frame. See
3281
- // / @ref mbp_working_with_free_bodies "above for details".
3356
+ // / @ref mbp_working_with_free_bodies "above for details".
3282
3357
// / @throws std::exception if `body` is not a free body in the model.
3358
+ // / @throws std::exception if the free body is not modeled with a
3359
+ // / QuaternionFloatingJoint.
3283
3360
// / @throws std::exception if called pre-finalize.
3361
+ // / @see SetFreeBodyRandomAnglesDistribution() for a free body that is
3362
+ // / modeled using an RpyFloatingJoint.
3363
+ // / @see SetBaseBodyJointType() for control over the type of automatically-
3364
+ // / added joints.
3284
3365
void SetFreeBodyRandomRotationDistributionToUniform (const RigidBody<T>& body);
3285
3366
3367
+ // / Sets the distribution used by SetRandomState() to populate the free
3368
+ // / body's orientation with respect to its parent frame, expressed with
3369
+ // / roll-pitch-yaw angles. Requires that the free body is modeled using an
3370
+ // / RpyFloatingJoint.
3371
+ // / @note The parent frame is not necessarily the world frame. See
3372
+ // / @ref mbp_working_with_free_bodies "above for details".
3373
+ // / @note This distribution is not uniform over the sphere reachable by
3374
+ // / the three angles. For a uniform alternative, switch the joint to
3375
+ // / QuaternionFloatingJoint and use
3376
+ // / SetFreeBodyRandomRotationDistributionToUniform().
3377
+ // / @throws std::exception if `body` is not a free body in the model.
3378
+ // / @throws std::exception if the free body is not modeled with an
3379
+ // / RpyFloatingJoint.
3380
+ // / @throws std::exception if called pre-finalize.
3381
+ // / @see SetFreeBodyRandomRotationDistribution() for a free body that is
3382
+ // / modeled using a QuaternionFloatingJoint.
3383
+ // / @see SetBaseBodyJointType() for control over the type of automatically-
3384
+ // / added joints.
3385
+ void SetFreeBodyRandomAnglesDistribution (
3386
+ const RigidBody<T>& body,
3387
+ const math::RollPitchYaw<symbolic::Expression>& angles) {
3388
+ this ->mutable_tree ().SetFreeBodyRandomAnglesDistributionOrThrow (body,
3389
+ angles);
3390
+ }
3391
+
3286
3392
// / Sets `context` to store the pose `X_WB` of a given _floating base_ `body`
3287
3393
// / B in the world frame W.
3288
3394
// / @param[in] context
0 commit comments