-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[multibody] Simplify frames in MultibodyPlant #21853
Conversation
8f3a3a3
to
e39366f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+@joemasterjohn please LMK if you have time and interest to feature review this. It simplifies the Frame classes and caches poses so we can use inline references. Provides a modest performance boost, see PR description for benchmark data.
Reviewable status: LGTM missing from assignee joemasterjohn, needs platform reviewer assigned, needs at least two assigned reviewers, labeled "do not merge", missing label for release notes (waiting on @sherm1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking a look now.
Reviewable status: LGTM missing from assignee joemasterjohn, needs platform reviewer assigned, needs at least two assigned reviewers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! This is super clean, so not much to say on my part. I sprinkled a few thoughts, but all nits.
Reviewed 14 of 14 files at r1, all commit messages.
Reviewable status: 3 unresolved discussions, needs platform reviewer assigned, needs at least two assigned reviewers
multibody/tree/frame_body_pose_cache.h
line 3 at r1 (raw file):
#pragma once #include <memory>
nit: Unused?
Code quote:
#include <memory>
multibody/tree/multibody_tree.cc
line 1397 at r1 (raw file):
} frame_body_poses->set_X_BF(body_pose_index_in_cache, frame->CalcPoseInBodyFrame(context));
Super nit picky, but calling CalcPoseInBodyFrame()
on each frame ends up recomputing the frame compositions all the way up the antecedents each time. If we processed the frames in topological order or just memoized X_BP
for a frame F
with parent P
we could avoid recomputing X_BP
when computing X_BF (= X_BP * X_PF)
. Of course this is only becomes a performance issue with super long chains of offset frames. Maybe just worth noting in a comment though? Whatever you think.
Code quote:
frame_body_poses->set_X_BF(body_pose_index_in_cache,
frame->CalcPoseInBodyFrame(context));
multibody/tree/test/frames_test.cc
line 290 at r1 (raw file):
R_BG, kEpsilon)); // Change the poses of the parent P and frame Q and make sure those are
nit: Is there an easy way to detect that a cached quantity has not been recomputed from the context of user level code like this? I was just thinking it would be nice to assert that a change to state doesn't recompute X_BF
when EvalPoseInBodyFrame()
gets called, to show the more granular dependency is working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+@xuchenhan-tri for platform review, please.
Reviewable status: 3 unresolved discussions, LGTM missing from assignee xuchenhan-tri(platform)
e39366f
to
2ca65e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feature review comments addressed, PTAL. Thanks @joemasterjohn !
Reviewable status: 1 unresolved discussion, LGTM missing from assignee xuchenhan-tri(platform)
multibody/tree/frame_body_pose_cache.h
line 3 at r1 (raw file):
Previously, joemasterjohn (Joe Masterjohn) wrote…
nit: Unused?
Done
multibody/tree/multibody_tree.cc
line 1397 at r1 (raw file):
Previously, joemasterjohn (Joe Masterjohn) wrote…
Super nit picky, but calling
CalcPoseInBodyFrame()
on each frame ends up recomputing the frame compositions all the way up the antecedents each time. If we processed the frames in topological order or just memoizedX_BP
for a frameF
with parentP
we could avoid recomputingX_BP
when computingX_BF (= X_BP * X_PF)
. Of course this is only becomes a performance issue with super long chains of offset frames. Maybe just worth noting in a comment though? Whatever you think.
Yeah, I thought of that too. I talked myself into doing this way based on (a) only doing this when parameters change, (b) likely only short offset frame stacks so not too much recalculation and (c) no convenient data structure around for doing this in a nice order. Added a TODO for now, PTAL. WDYT?
multibody/tree/test/frames_test.cc
line 290 at r1 (raw file):
Previously, joemasterjohn (Joe Masterjohn) wrote…
nit: Is there an easy way to detect that a cached quantity has not been recomputed from the context of user level code like this? I was just thinking it would be nice to assert that a change to state doesn't recompute
X_BF
whenEvalPoseInBodyFrame()
gets called, to show the more granular dependency is working.
Done. Good idea. Requires a little caching-fu.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 13 of 14 files at r1, 3 of 3 files at r2, all commit messages.
Reviewable status: 2 unresolved discussions
multibody/tree/frame_base.h
line 51 at r1 (raw file):
/// @tparam_default_scalar template <typename T> class FrameBase : public MultibodyElement<T> {
This class is a part of public APIs. Is there a good reason why we aren't deprecating this? In any case, the release note label should be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 3 of 3 files at r2, all commit messages.
Reviewable status: 1 unresolved discussion
multibody/tree/multibody_tree.cc
line 1397 at r1 (raw file):
Previously, sherm1 (Michael Sherman) wrote…
Yeah, I thought of that too. I talked myself into doing this way based on (a) only doing this when parameters change, (b) likely only short offset frame stacks so not too much recalculation and (c) no convenient data structure around for doing this in a nice order. Added a TODO for now, PTAL. WDYT?
Totally agree. Thanks for the comment.
multibody/tree/test/frames_test.cc
line 290 at r1 (raw file):
Previously, sherm1 (Michael Sherman) wrote…
Done. Good idea. Requires a little caching-fu.
Awesome, looks great. I thought it might be doable given the access to the MultibodyTreeSystem
in this unit test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 1 unresolved discussion
multibody/tree/frame_base.h
line 51 at r1 (raw file):
Previously, xuchenhan-tri wrote…
This class is a part of public APIs. Is there a good reason why we aren't deprecating this? In any case, the release note label should be updated.
Done, thanks. Good point. Technically this is a breaking change so I changed the release note to that. However, there were no uses of this class in Drake or Anzu, no Python bindings, and no functionality so I believe it is harmless and not worth deprecating. I added a note about that in the PR description for the next release, PTAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @xuchenhan-tri -- I addressed your comment, WDYT?
Reviewable status: 1 unresolved discussion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as long as you are confident that no one is depending on the FrameBase class.
Reviewable status: 1 unresolved discussion
-- commits
line 4 at r2:
BTW, I think the release engineer only sees the commit message (but not the PR description), consider moving the note about the breaking change here.
multibody/tree/frame_base.h
line 51 at r1 (raw file):
If we are sure that no one is relying this, then I think a breaking change is fine. Otherwise, we should deprecate because our guidelines do say that a breaking change is "very rare".
On very rare occasions it is impractical, too expensive, or logically unsound to meet the full three month deprecation window. In these cases the change will be announced in the “Breaking changes” section of the release notes.
Convert BodyNode functions to use the new cache. Release note: FrameBase is gone. In theory it could have appeared somewhere, but in practice Drake and Anzu never mentioned it and it had no functionality. Worth noting in the release notes as a very unlikely breaking change.
2ca65e8
to
5253567
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status:
complete! all discussions resolved, LGTM from assignees joemasterjohn,xuchenhan-tri(platform)
Previously, xuchenhan-tri wrote…
BTW, I think the release engineer only sees the commit message (but not the PR description), consider moving the note about the breaking change here.
Done
multibody/tree/frame_base.h
line 51 at r1 (raw file):
Previously, xuchenhan-tri wrote…
If we are sure that no one is relying this, then I think a breaking change is fine. Otherwise, we should deprecate because our guidelines do say that a breaking change is "very rare".
On very rare occasions it is impractical, too expensive, or logically unsound to meet the full three month deprecation window. In these cases the change will be announced in the “Breaking changes” section of the release notes.
I know we're not using it internally, and since the class has no functionality there is no sane reason to mention it rather than starting with Frame as in all our examples. So IMO no deprecation needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed all commit messages.
Reviewable status:complete! all discussions resolved, LGTM from assignees joemasterjohn,xuchenhan-tri(platform)
multibody/tree/frame_base.h
line 51 at r1 (raw file):
Previously, sherm1 (Michael Sherman) wrote…
I know we're not using it internally, and since the class has no functionality there is no sane reason to mention it rather than starting with Frame as in all our examples. So IMO no deprecation needed.
SGTM!
…otion#21853) Convert BodyNode functions to use the new cache. Release note: FrameBase is gone. In theory it could have appeared somewhere, but in practice Drake and Anzu never mentioned it and it had no functionality. Worth noting in the release notes as a very unlikely breaking change.
This is a small step towards a high-performance multibody kernel, see issue #18442. An important goal is to eliminate Context spelunking and virtual methods from the multibody kernel; this moves us part way there and provides a modest performance boost (benchmarks below).
Background
The Frame class hierarchy was originally designed to support frames on deformable bodies, supporting the notion that a frame's pose on its body might not be constant. We don't need that abstraction now -- all our Frames have fixed poses after parameters have been set (they are either RigidBodyFrames or FixedOffsetFrames). There is overhead associated with that abstraction -- virtual methods, runtime recalculations of pose, and copies rather than references.
What's here
This PR removes the deformable-frame abstraction and then takes advantage of that to cache Frame pose information as soon as parameters are set rather than at run time. Specifically:
What's not here
Release note
Although FrameBase was a public class it had no functionality and served only as the useless base class for Frame. There are no direct uses of FrameBase in Drake or Anzu, and no Python bindings. So although this is technically a breaking change I'm not deprecating it because there is ~zero chance anyone will be affected.
Benchmarking
CassieBench measures only multibody kernel time, in microseconds.
AutoDiff and Expression benchmarks were not measurably affected by this change.
This change is