-
Notifications
You must be signed in to change notification settings - Fork 41
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
Minor optimization for picking contact points in dartsim's ODE collision detector #584
Changes from all commits
e01a252
72ad146
e0d0cb1
fa9830f
9cc40ae
1016ec0
c428a3c
52af0a2
a2bcbf0
9da1af3
98b5e61
af1655c
da72c73
e4e51e1
b140329
2e97b18
89d6347
20ccc51
6e57e47
b9e3fa6
115b541
628a9b6
b5592a4
93ec7a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -223,9 +223,13 @@ TYPED_TEST(SimulationFeaturesContactsTest, Contacts) | |
// The features that an engine must have to be loaded by this loader. | ||
struct FeaturesCollisionPairMaxContacts : gz::physics::FeatureList< | ||
gz::physics::sdf::ConstructSdfWorld, | ||
gz::physics::GetContactsFromLastStepFeature, | ||
gz::physics::CollisionPairMaxContacts, | ||
gz::physics::FindFreeGroupFeature, | ||
gz::physics::ForwardStep, | ||
gz::physics::CollisionPairMaxContacts | ||
gz::physics::FreeGroupFrameSemantics, | ||
gz::physics::GetContactsFromLastStepFeature, | ||
gz::physics::GetModelFromWorld, | ||
gz::physics::SetFreeGroupWorldPose | ||
> {}; | ||
|
||
template <class T> | ||
|
@@ -276,6 +280,92 @@ TYPED_TEST(SimulationFeaturesCollisionPairMaxContactsTest, | |
} | ||
} | ||
|
||
///////////////////////////////////////////////// | ||
TYPED_TEST(SimulationFeaturesCollisionPairMaxContactsTest, | ||
CollisionPairMaxContactsSelection) | ||
{ | ||
for (const std::string &name : this->pluginNames) | ||
{ | ||
auto world = LoadPluginAndWorld<FeaturesCollisionPairMaxContacts>( | ||
this->loader, | ||
name, | ||
common_test::worlds::kCollisionPairContactPointSdf); | ||
auto checkedOutput = StepWorld<FeaturesCollisionPairMaxContacts>( | ||
world, true, 1).first; | ||
EXPECT_TRUE(checkedOutput); | ||
|
||
// Verify initial pose | ||
const gz::math::Pose3d initialPose = gz::math::Pose3d::Zero; | ||
auto ellipsoid = world->GetModel("ellipsoid"); | ||
ASSERT_NE(nullptr, ellipsoid); | ||
auto ellipsoidFreeGroup = ellipsoid->FindFreeGroup(); | ||
ASSERT_NE(nullptr, ellipsoidFreeGroup); | ||
auto box = world->GetModel("box"); | ||
ASSERT_NE(nullptr, box); | ||
auto boxFreeGroup = box->FindFreeGroup(); | ||
ASSERT_NE(nullptr, boxFreeGroup); | ||
auto ellipsoidFrameData = ellipsoidFreeGroup->FrameDataRelativeToWorld(); | ||
auto boxFrameData = boxFreeGroup->FrameDataRelativeToWorld(); | ||
EXPECT_EQ(initialPose, | ||
gz::math::eigen3::convert(ellipsoidFrameData.pose)); | ||
EXPECT_EQ(initialPose, | ||
gz::math::eigen3::convert(boxFrameData.pose)); | ||
|
||
// Get all contacts between box and ellipsoid | ||
auto contacts = world->GetContactsFromLastStep(); | ||
EXPECT_EQ(std::numeric_limits<std::size_t>::max(), | ||
world->GetCollisionPairMaxContacts()); | ||
EXPECT_GT(contacts.size(), 30u); | ||
|
||
// Find contact point with max penetration depth | ||
double maxDepth = 0; | ||
for (const auto &contact : contacts) | ||
{ | ||
const auto* extraContactData = | ||
contact.template Query< | ||
gz::physics::World3d< | ||
FeaturesCollisionPairMaxContacts>::ExtraContactData>(); | ||
ASSERT_NE(nullptr, extraContactData); | ||
if (extraContactData->depth > maxDepth) | ||
maxDepth = extraContactData->depth; | ||
} | ||
EXPECT_GT(maxDepth, 0.0); | ||
|
||
// Reset pose back to initial pose | ||
ellipsoidFreeGroup->SetWorldPose( | ||
gz::math::eigen3::convert(initialPose)); | ||
boxFreeGroup->SetWorldPose( | ||
gz::math::eigen3::convert(initialPose)); | ||
ellipsoidFrameData = ellipsoidFreeGroup->FrameDataRelativeToWorld(); | ||
boxFrameData = boxFreeGroup->FrameDataRelativeToWorld(); | ||
|
||
EXPECT_EQ(initialPose, | ||
gz::math::eigen3::convert(ellipsoidFrameData.pose)); | ||
EXPECT_EQ(initialPose, | ||
gz::math::eigen3::convert(boxFrameData.pose)); | ||
|
||
// Set max contact between collision pairs to be 1 | ||
world->SetCollisionPairMaxContacts(1u); | ||
EXPECT_EQ(1u, world->GetCollisionPairMaxContacts()); | ||
checkedOutput = StepWorld<FeaturesCollisionPairMaxContacts>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this test assumes that the objects will be at the same position for both time steps, which would be the case if the Maybe it would be more repeatable in general if we explicitly reset the object poses to the same value before each step? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok makes sense. I updated the test to reset the objects to their initial pose between steps. 115b541 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @scpeters friendly ping, does this look good to you? |
||
world, true, 1).first; | ||
EXPECT_TRUE(checkedOutput); | ||
|
||
contacts = world->GetContactsFromLastStep(); | ||
EXPECT_EQ(1u, contacts.size()); | ||
|
||
// Verify that the physics engine picked the contact with max penetration | ||
// depth | ||
auto contact = contacts[0]; | ||
const auto* extraContactData = | ||
contact.template Query< | ||
gz::physics::World3d< | ||
FeaturesCollisionPairMaxContacts>::ExtraContactData>(); | ||
ASSERT_NE(nullptr, extraContactData); | ||
EXPECT_FLOAT_EQ(maxDepth, extraContactData->depth); | ||
} | ||
} | ||
|
||
// The features that an engine must have to be loaded by this loader. | ||
struct FeaturesStep : gz::physics::FeatureList< | ||
gz::physics::sdf::ConstructSdfWorld, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?xml version="1.0" ?> | ||
<sdf version="1.6"> | ||
<world name="default"> | ||
|
||
<model name="box"> | ||
<static>true</static> | ||
<pose>0 0 0.0 0 0 0</pose> | ||
<link name="box_link"> | ||
<inertial> | ||
<inertia> | ||
<ixx>1</ixx> | ||
<ixy>0</ixy> | ||
<ixz>0</ixz> | ||
<iyy>1</iyy> | ||
<iyz>0</iyz> | ||
<izz>1</izz> | ||
</inertia> | ||
<mass>1.0</mass> | ||
</inertial> | ||
<collision name="box_collision"> | ||
<geometry> | ||
<box> | ||
<size>100 100 1</size> | ||
</box> | ||
</geometry> | ||
</collision> | ||
<visual name="box_visual"> | ||
<geometry> | ||
<box> | ||
<size>100 100 1</size> | ||
</box> | ||
</geometry> | ||
</visual> | ||
</link> | ||
</model> | ||
|
||
<model name="ellipsoid"> | ||
<pose>0 -0 0.0 0 0 0</pose> | ||
<link name="ellipsoid_link"> | ||
<inertial> | ||
<inertia> | ||
<ixx>0.068</ixx> | ||
<ixy>0</ixy> | ||
<ixz>0</ixz> | ||
<iyy>0.058</iyy> | ||
<iyz>0</iyz> | ||
<izz>0.026</izz> | ||
</inertia> | ||
<mass>1.0</mass> | ||
</inertial> | ||
<collision name="ellipsoid_collision"> | ||
<geometry> | ||
<ellipsoid> | ||
<radii>0.2 0.3 0.5</radii> | ||
</ellipsoid> | ||
</geometry> | ||
</collision> | ||
<visual name="ellipsoid_visual"> | ||
<geometry> | ||
<ellipsoid> | ||
<radii>0.2 0.3 0.5</radii> | ||
</ellipsoid> | ||
</geometry> | ||
</visual> | ||
</link> | ||
</model> | ||
</world> | ||
</sdf> |
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.
this does match what gazebo-classic was doing, so I think it's a reasonable place to start, but reading this code raises questions for me about what should be done.
One approach could be to sort contacts by penetration depth and choose the points with the maximum depth values, but then you could still have to choose between points if their depth values were identical. Then again, the computational cost must also be considered
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.
yeah I think that's a good approach and see if how that much extra sorting logic costs. We can consider this as a follow up improvement?
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.
👍