Skip to content

Commit dd368b0

Browse files
committed
Allow floating bodies to use RpyFloating joints.
Also supports using Weld joints instead of floating joints for unattached bodies.
1 parent 738bbcf commit dd368b0

21 files changed

+1014
-168
lines changed

multibody/plant/multibody_plant.cc

+22-1
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ void MultibodyPlant<T>::SetFreeBodyPoseInAnchoredFrame(
11751175
}
11761176

11771177
// Pose of frame F in its parent body frame P.
1178-
const RigidTransform<T> X_PF = frame_F.GetFixedPoseInBodyFrame();
1178+
const RigidTransform<T>& X_PF = frame_F.EvalPoseInBodyFrame(*context);
11791179
// Pose of frame F's parent body P in the world.
11801180
const RigidTransform<T>& X_WP = EvalBodyPoseInWorld(*context, frame_F.body());
11811181
// Pose of "body" B in the world frame.
@@ -1266,6 +1266,27 @@ void MultibodyPlant<T>::RenameModelInstance(ModelInstanceIndex model_instance,
12661266
}
12671267
}
12681268

1269+
template <typename T>
1270+
void MultibodyPlant<T>::SetBaseBodyJointType(
1271+
BaseBodyJointType joint_type,
1272+
std::optional<ModelInstanceIndex> model_instance) {
1273+
static const std::map<BaseBodyJointType, internal::ForestBuildingOptions>
1274+
option_map{{BaseBodyJointType::kQuaternionFloatingJoint,
1275+
internal::ForestBuildingOptions::kDefault},
1276+
{BaseBodyJointType::kRpyFloatingJoint,
1277+
internal::ForestBuildingOptions::kUseRpyFloatingJoints},
1278+
{BaseBodyJointType::kWeldJoint,
1279+
internal::ForestBuildingOptions::kUseFixedBase}};
1280+
DRAKE_DEMAND(option_map.contains(joint_type));
1281+
DRAKE_THROW_UNLESS(!is_finalized());
1282+
internal::LinkJointGraph& graph = mutable_tree().mutable_graph();
1283+
if (model_instance.has_value()) {
1284+
graph.SetForestBuildingOptions(*model_instance, option_map.at(joint_type));
1285+
} else {
1286+
graph.SetGlobalForestBuildingOptions(option_map.at(joint_type));
1287+
}
1288+
}
1289+
12691290
template <typename T>
12701291
void MultibodyPlant<T>::Finalize() {
12711292
// After finalizing the base class, tree is read-only.

multibody/plant/multibody_plant.h

+88-5
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,14 @@ enum class DiscreteContactApproximation {
228228
kLagged,
229229
};
230230

231+
/// The kind of joint to be used to connect free bodies to world at Finalize().
232+
/// @see SetBaseBodyJointType() for details.
233+
enum class BaseBodyJointType {
234+
kQuaternionFloatingJoint, ///< 6 dofs, unrestricted orientation.
235+
kRpyFloatingJoint, ///< 6 dofs using 3 angles; has singularity.
236+
kWeldJoint, ///< 0 dofs, fixed to World.
237+
};
238+
231239
/// @cond
232240
// Helper macro to throw an exception within methods that should not be called
233241
// post-finalize.
@@ -1667,6 +1675,39 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
16671675
void RenameModelInstance(ModelInstanceIndex model_instance,
16681676
const std::string& name);
16691677

1678+
/// Sets the type of joint to be used by Finalize() to connect any otherwise
1679+
/// unconnected bodies to World. Bodies connected by a joint to World are
1680+
/// called _base bodies_ and are determined during Finalize() when we build
1681+
/// a forest structure to model the multibody system for efficient
1682+
/// computation.
1683+
///
1684+
/// This can be set globally or for a particular model instance. Global
1685+
/// options are used for any model elements that belong to model instances for
1686+
/// which no options have been set explicitly. The default is to use a
1687+
/// quaternion floating joint.
1688+
///
1689+
/// | BaseBodyJointType:: | Notes |
1690+
/// | ------------------------ | -------------------------------------- |
1691+
/// | kQuaternionFloatingJoint | 6 dofs, unrestricted orientation |
1692+
/// | kRpyFloatingJoint † | 6 dofs, uses 3 angles for orientation |
1693+
/// | kWeldJoint | 0 dofs, welded to World ("anchored") |
1694+
///
1695+
/// † The 3-angle orientation representation used by RpyFloatingJoint can be
1696+
/// easier to work with than a quaternion (especially for optimization) but
1697+
/// has a singular orientation which must be avoided (pitch angle near 90°).
1698+
///
1699+
/// @note Reminder: if you aren't satisfied with the automatic choice of
1700+
/// base body or the particular selection of joints here, you can always
1701+
/// add an explicit joint to World with AddJoint().
1702+
///
1703+
/// @param[in] joint_type The joint type to be used for base bodies.
1704+
/// @param[in] model_instance (optional) the index of the model instance to
1705+
/// which `joint_type` is to be applied.
1706+
/// @throws std::exception if called after Finalize().
1707+
void SetBaseBodyJointType(
1708+
BaseBodyJointType joint_type,
1709+
std::optional<ModelInstanceIndex> model_instance = {});
1710+
16701711
/// This method must be called after all elements in the model (joints,
16711712
/// bodies, force elements, constraints, etc.) are added and before any
16721713
/// computations are performed.
@@ -3217,11 +3258,22 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
32173258
}
32183259

32193260
/// Sets the distribution used by SetRandomState() to populate the free
3220-
/// body's `rotation` with respect to its parent frame.
3261+
/// body's orientation with respect to its parent frame, expressed as a
3262+
/// quaternion. Requires that the free body is modeled using a
3263+
/// QuaternionFloatingJoint.
32213264
/// @note The parent frame is not necessarily the world frame. See
3222-
/// @ref mbp_working_with_free_bodies "above for details".
3265+
/// @ref mbp_working_with_free_bodies "above for details".
3266+
/// @note This distribution is not uniform over the sphere reachable by
3267+
/// the quaternion. See SetFreeBodyRandomRotationDistributionToUniform()
3268+
/// for a uniform alternative.
32233269
/// @throws std::exception if `body` is not a free body in the model.
3270+
/// @throws std::exception if the free body is not modeled with a
3271+
/// QuaternionFloatingJoint.
32243272
/// @throws std::exception if called pre-finalize.
3273+
/// @see SetFreeBodyRandomAnglesDistribution() for a free body that is
3274+
/// modeled using an RpyFloatingJoint.
3275+
/// @see SetBaseBodyJointType() for control over the type of automatically-
3276+
/// added joints.
32253277
void SetFreeBodyRandomRotationDistribution(
32263278
const RigidBody<T>& body,
32273279
const Eigen::Quaternion<symbolic::Expression>& rotation) {
@@ -3230,14 +3282,45 @@ class MultibodyPlant : public internal::MultibodyTreeSystem<T> {
32303282
}
32313283

32323284
/// Sets the distribution used by SetRandomState() to populate the free
3233-
/// body's rotation with respect to its parent frame using uniformly random
3234-
/// rotations.
3285+
/// body's orientation with respect to its parent frame using uniformly random
3286+
/// rotations (expressed as a quaternion). Requires that the free body is
3287+
/// modeled using a QuaternionFloatingJoint.
32353288
/// @note The parent frame is not necessarily the world frame. See
3236-
/// @ref mbp_working_with_free_bodies "above for details".
3289+
/// @ref mbp_working_with_free_bodies "above for details".
32373290
/// @throws std::exception if `body` is not a free body in the model.
3291+
/// @throws std::exception if the free body is not modeled with a
3292+
/// QuaternionFloatingJoint.
32383293
/// @throws std::exception if called pre-finalize.
3294+
/// @see SetFreeBodyRandomAnglesDistribution() for a free body that is
3295+
/// modeled using an RpyFloatingJoint.
3296+
/// @see SetBaseBodyJointType() for control over the type of automatically-
3297+
/// added joints.
32393298
void SetFreeBodyRandomRotationDistributionToUniform(const RigidBody<T>& body);
32403299

3300+
/// Sets the distribution used by SetRandomState() to populate the free
3301+
/// body's orientation with respect to its parent frame, expressed with
3302+
/// roll-pitch-yaw angles. Requires that the free body is modeled using an
3303+
/// RpyFloatingJoint.
3304+
/// @note The parent frame is not necessarily the world frame. See
3305+
/// @ref mbp_working_with_free_bodies "above for details".
3306+
/// @note This distribution is not uniform over the sphere reachable by
3307+
/// the three angles. See SetFreeBodyRandomRotationDistributionToUniform()
3308+
/// for a uniform alternative.
3309+
/// @throws std::exception if `body` is not a free body in the model.
3310+
/// @throws std::exception if the free body is not modeled with an
3311+
/// RpyFloatingJoint.
3312+
/// @throws std::exception if called pre-finalize.
3313+
/// @see SetFreeBodyRandomRotationDistribution() for a free body that is
3314+
/// modeled using a QuaternionFloatingJoint.
3315+
/// @see SetBaseBodyJointType() for control over the type of automatically-
3316+
/// added joints.
3317+
void SetFreeBodyRandomAnglesDistribution(
3318+
const RigidBody<T>& body,
3319+
const math::RollPitchYaw<symbolic::Expression>& angles) {
3320+
this->mutable_tree().SetFreeBodyRandomAnglesDistributionOrThrow(body,
3321+
angles);
3322+
}
3323+
32413324
/// Sets `context` to store the pose `X_WB` of a given _floating base_ `body`
32423325
/// B in the world frame W.
32433326
/// @param[in] context

multibody/plant/test/floating_body_test.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ namespace internal {
1717
class MultibodyTreeTester {
1818
public:
1919
MultibodyTreeTester() = delete;
20+
2021
static const QuaternionFloatingMobilizer<double>& get_floating_mobilizer(
2122
const MultibodyTree<double>& model, const RigidBody<double>& body) {
22-
return model.GetFreeBodyMobilizerOrThrow(body);
23+
const Mobilizer<double>& mobilizer =
24+
model.GetFreeBodyMobilizerOrThrow(body);
25+
const QuaternionFloatingMobilizer<double>* const
26+
quaternion_floating_mobilizer =
27+
dynamic_cast<const QuaternionFloatingMobilizer<double>*>(
28+
&mobilizer);
29+
DRAKE_DEMAND(quaternion_floating_mobilizer != nullptr);
30+
return *quaternion_floating_mobilizer;
2331
}
2432
};
2533
} // namespace internal

0 commit comments

Comments
 (0)