Skip to content

Commit ee1045d

Browse files
iche033mergify[bot]
authored andcommitted
bullet-featherstone: Fix get contacts (#838)
Signed-off-by: Ian Chen <ichen@openrobotics.org> Co-authored-by: Addisu Z. Taddese <addisu@openrobotics.org> (cherry picked from commit 00e0fdd) # Conflicts: # bullet-featherstone/src/SimulationFeatures.cc
1 parent 1f21852 commit ee1045d

3 files changed

Lines changed: 300 additions & 28 deletions

File tree

bullet-featherstone/src/SDFFeatures.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,12 +1351,18 @@ bool SDFFeatures::AddSdfCollision(
13511351
// match the existing collider and issue a warning if they don't.
13521352
}
13531353

1354-
this->AddCollision(
1354+
btCollisionShape *shapePtr = shape.get();
1355+
auto colID = this->AddCollision(
13551356
CollisionInfo{
13561357
_collision.Name(),
13571358
std::move(shape),
13581359
_linkID,
13591360
linkFrameToCollision});
1361+
1362+
// Use user index to store the collision id in gz-physics
1363+
// This is used by GetContactsFromLastStep to retrieve the collision id
1364+
// from btCollisionShape
1365+
shapePtr->setUserIndex(std::size_t(colID));
13601366
}
13611367

13621368
return true;

bullet-featherstone/src/SimulationFeatures.cc

Lines changed: 172 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,143 @@ namespace physics {
2828
namespace bullet_featherstone {
2929

3030
/////////////////////////////////////////////////
31+
<<<<<<< HEAD
32+
=======
33+
bool hasConvexHullChildShapes(
34+
const btCollisionShape *_shape)
35+
{
36+
if (!_shape || !_shape->isCompound())
37+
return false;
38+
39+
const btCompoundShape *compoundShape =
40+
static_cast<const btCompoundShape *>(_shape);
41+
return (compoundShape->getNumChildShapes() > 0 &&
42+
compoundShape->getChildShape(0)->getShapeType() ==
43+
CONVEX_HULL_SHAPE_PROXYTYPE);
44+
}
45+
46+
/////////////////////////////////////////////////
47+
const btCollisionShape *findCollisionShape(
48+
const btCompoundShape *_compoundShape, int _childIndex)
49+
{
50+
// _childIndex should give us the index of the child shape within
51+
// _compoundShape which represents the collision.
52+
// One exception is when the collision is a convex decomposed mesh.
53+
// In this case, the child shape is another btCompoundShape (nested), and
54+
// _childIndex is the index of one of the decomposed convex hulls
55+
// in the nested compound shape. The nested compound shape is the collision.
56+
int childCount = _compoundShape->getNumChildShapes();
57+
if (childCount > 0)
58+
{
59+
if (_childIndex >= 0 && _childIndex < childCount)
60+
{
61+
// todo(iche033) We do not have sufficient info to determine which
62+
// child shape is the collision if the link has convex decomposed mesh
63+
// collisions alongside of other collisions. See following example:
64+
// parentLink -> boxShape0
65+
// -> boxShape1
66+
// -> compoundShape -> convexShape0
67+
// -> convexShape1
68+
// A _childIndex of 1 is ambiguous as it could refer to either
69+
// boxShape1 or convexShape1
70+
// return nullptr in this case to indicate ambiguity
71+
if (childCount > 1)
72+
{
73+
for (int i = 0; i < childCount; ++i)
74+
{
75+
const btCollisionShape *shape = _compoundShape->getChildShape(i);
76+
if (hasConvexHullChildShapes(shape))
77+
{
78+
static bool informed{false};
79+
if (!informed)
80+
{
81+
gzwarn << "Unable to determine the collision id for a link with "
82+
<< "both simple primitive and convex shape collisions."
83+
<< std::endl;
84+
informed = true;
85+
}
86+
return nullptr;
87+
}
88+
}
89+
}
90+
91+
const btCollisionShape *shape =
92+
_compoundShape->getChildShape(_childIndex);
93+
return shape;
94+
}
95+
else
96+
{
97+
return _compoundShape->getChildShape(0);
98+
}
99+
}
100+
return nullptr;
101+
}
102+
103+
/////////////////////////////////////////////////
104+
void enforceFixedConstraint(
105+
btMultiBodyFixedConstraint *_fixedConstraint)
106+
{
107+
// Update fixed constraint's child link pose to maintain a fixed transform
108+
// from the parent link.
109+
GzMultiBody *parent =
110+
dynamic_cast<GzMultiBody*> (_fixedConstraint->getMultiBodyA());
111+
if (parent == nullptr)
112+
{
113+
std::cerr << "Internal error: Failed to cast parent btMultiBody to "
114+
"GzMultiBody!" << std::endl;
115+
return;
116+
}
117+
118+
GzMultiBody *child =
119+
dynamic_cast<GzMultiBody*> (_fixedConstraint->getMultiBodyB());
120+
if (child == nullptr)
121+
{
122+
std::cerr << "Internal error: Failed to cast child btMultiBody to "
123+
"GzMultiBody!" << std::endl;
124+
return;
125+
}
126+
127+
btTransform parentToChildTf;
128+
parentToChildTf.setOrigin(_fixedConstraint->getPivotInA());
129+
parentToChildTf.setBasis(_fixedConstraint->getFrameInA());
130+
131+
int parentLinkIndex = _fixedConstraint->getLinkA();
132+
int childLinkIndex = _fixedConstraint->getLinkB();
133+
134+
btTransform parentLinkTf;
135+
btTransform childLinkTf;
136+
if (parentLinkIndex == -1)
137+
{
138+
parentLinkTf = parent->getBaseWorldTransform();
139+
}
140+
else
141+
{
142+
btMultiBodyLinkCollider *collider =
143+
parent->getLinkCollider(parentLinkIndex);
144+
parentLinkTf = collider->getWorldTransform();
145+
}
146+
if (childLinkIndex == -1)
147+
{
148+
childLinkTf = child->getBaseWorldTransform();
149+
}
150+
else
151+
{
152+
btMultiBodyLinkCollider *collider =
153+
child->getLinkCollider(childLinkIndex);
154+
childLinkTf = collider->getWorldTransform();
155+
}
156+
157+
btTransform expectedChildLinkTf = parentLinkTf * parentToChildTf;
158+
btTransform childBaseTf = child->getBaseWorldTransform();
159+
btTransform childBaseToLink =
160+
childBaseTf.inverse() * childLinkTf;
161+
btTransform newChildBaseTf =
162+
expectedChildLinkTf * childBaseToLink.inverse();
163+
child->SetBaseWorldTransform(newChildBaseTf);
164+
}
165+
166+
/////////////////////////////////////////////////
167+
>>>>>>> 00e0fdd (bullet-featherstone: Fix get contacts (#838))
31168
void SimulationFeatures::WorldForwardStep(
32169
const Identity &_worldID,
33170
ForwardStep::Output & _h,
@@ -112,34 +249,47 @@ SimulationFeatures::GetContactsFromLastStep(const Identity &_worldID) const
112249
{
113250
btPersistentManifold* contactManifold =
114251
world->world->getDispatcher()->getManifoldByIndexInternal(i);
115-
const btMultiBodyLinkCollider* obA =
252+
const btMultiBodyLinkCollider* ob0 =
116253
dynamic_cast<const btMultiBodyLinkCollider*>(contactManifold->getBody0());
117-
const btMultiBodyLinkCollider* obB =
254+
const btMultiBodyLinkCollider* ob1 =
118255
dynamic_cast<const btMultiBodyLinkCollider*>(contactManifold->getBody1());
119-
std::size_t collision1ID = std::numeric_limits<std::size_t>::max();
120-
std::size_t collision2ID = std::numeric_limits<std::size_t>::max();
121256

122-
for (const auto & link : this->links)
123-
{
124-
if (obA == link.second->collider.get())
125-
{
126-
for (const auto &v : link.second->collisionNameToEntityId)
127-
{
128-
collision1ID = v.second;
129-
}
130-
}
131-
if (obB == link.second->collider.get())
132-
{
133-
for (const auto &v : link.second->collisionNameToEntityId)
134-
{
135-
collision2ID = v.second;
136-
}
137-
}
138-
}
257+
if (!ob0 || !ob1)
258+
continue;
259+
260+
const btCollisionShape *linkShape0 = ob0->getCollisionShape();
261+
const btCollisionShape *linkShape1 = ob1->getCollisionShape();
262+
263+
if (!linkShape0 || !linkShape1 ||
264+
!linkShape0->isCompound() || !linkShape1->isCompound())
265+
continue;
266+
267+
const btCompoundShape *compoundShape0 =
268+
static_cast<const btCompoundShape *>(linkShape0);
269+
const btCompoundShape *compoundShape1 =
270+
static_cast<const btCompoundShape *>(linkShape1);
271+
139272
int numContacts = contactManifold->getNumContacts();
140273
for (int j = 0; j < numContacts; j++)
141274
{
142275
btManifoldPoint& pt = contactManifold->getContactPoint(j);
276+
277+
const btCollisionShape *colShape0 = findCollisionShape(
278+
compoundShape0, pt.m_index0);
279+
const btCollisionShape *colShape1 = findCollisionShape(
280+
compoundShape1, pt.m_index1);
281+
282+
std::size_t collision0ID = std::numeric_limits<std::size_t>::max();
283+
std::size_t collision1ID = std::numeric_limits<std::size_t>::max();
284+
if (colShape0)
285+
collision0ID = colShape0->getUserIndex();
286+
else if (compoundShape0->getNumChildShapes() > 0)
287+
collision0ID = compoundShape0->getChildShape(0)->getUserIndex();
288+
if (colShape1)
289+
collision1ID = colShape1->getUserIndex();
290+
else if (compoundShape1->getNumChildShapes() > 0)
291+
collision1ID = compoundShape1->getChildShape(0)->getUserIndex();
292+
143293
CompositeData extraData;
144294

145295
// Add normal, depth and wrench to extraData.
@@ -153,8 +303,8 @@ SimulationFeatures::GetContactsFromLastStep(const Identity &_worldID) const
153303
extraContactData.depth = pt.getDistance();
154304

155305
outContacts.push_back(SimulationFeatures::ContactInternal {
306+
this->GenerateIdentity(collision0ID, this->collisions.at(collision0ID)),
156307
this->GenerateIdentity(collision1ID, this->collisions.at(collision1ID)),
157-
this->GenerateIdentity(collision2ID, this->collisions.at(collision2ID)),
158308
convert(pt.getPositionWorldOnA()), extraData});
159309
}
160310
}

0 commit comments

Comments
 (0)