Skip to content
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

Individual bodies within compounds do not retain pointers to their positions #223

Open
apsabelhaus opened this issue Feb 17, 2018 · 3 comments
Labels

Comments

@apsabelhaus
Copy link
Member

The way that we, and Bullet, treat compound bodies, makes our current implementation of getCenterOfMass() incorrect when rigid bodies are within a compound.

Here's the problem:
When creating a compound in tgcreator, we make a btCompoundShape (of type btCollisionShape), which is then passed as the collision shape when constructing a btRigidBody. This way, btRigidBodies have exactly one collision shape, which is made up of compound shapes, one for each tgRigidBody we've specified.

However, since there's only one btRigidBody within a compound, that means that the getPRigidBody() method for ANY shape within a single compound returns a pointer to the WHOLE btRigidBody. In effect, this means that we've got (for example), tgSpheres, tgRods, tgBoxes, etc. which are different in NTRT but are the same in Bullet Physics.

Practically: when calling getCenterOfMass() from a tgRigidBody, that gets the COM of its btRigidBody. So, when two tgRigidBodies are in a compound, getCenterOfMass() returns the center of mass of the entire compound, NOT each individual element.

Example: make a sphere on a stick, have them auto-compounded, and call getCenterOfMass() on each of them (as tgModels()) anywhere within NTRT. You'll get the same value (the COM of the compound.)

The only way to differentiate between components within a compound is to get the btCollisionShape of the rigid body (for any component), confirm it's a btCompoundShape, and try to get some information out of the child btCollisionShapes that make up that compound. (For the example suggested here - you can call getName() on the children and get back "SPHERE" and "CylinderY.")

This creates major issues with (1) consistency, since it's misleading to have centers of masses within NTRT that don't refer to individual objects, and (2) not seemingly possible to get the COM of each component in a compound.

I tried to pull out each btCollisionShape out of a btCompoundShape, and somehow get its transform with respect to the local frame of the compound (thinking we could call getCenterOfMass() for a compound then transform it individually to each component), but I couldn't seem to get it to work. Somehow, the pointers are all messed up with btCollisionShape's getChildTransform's getOrigin and getRotation methods.

Might try to use the btCompoundShape's calculatePrincipalAxisTransform() method, (https://pybullet.org/Bullet/phpBB3/viewtopic.php?p=&f=&t=11004), to do what we want.

For now, all sensor data for individual bodies, within compound bodies, is BROKEN in NTRT.

@ryan1248
Copy link
Contributor

ryan1248 commented Feb 18, 2018 via email

@apsabelhaus
Copy link
Member Author

Thanks Ryan! (PS - hope you're doing well!)

I'm working on a solution right now - won't get the COM of the components within a compound, but will get global node positions of any model, which is probably "good enough" and is what I really wanted anyway.

The general outline would be the following, inspired by Brian Mirletz' use of abstractMarker in his spines. Folks, let me know if there are unforeseen consequences here:

  1. tgModels have a local variable of tgNodes object (a copy, or maybe a const pointer to a const?) that contains all the nodes in the model, as originally passed in to a structure. These are local positions.
  2. In buildIntoHelper inside tgStructureInfo (I think that's where it is), the nodes from the structure are passed to the new tgModel after creation. That way, all nodes should be available in a model.
  3. tgModel can then have a method such as "getNodesGlobalPosition()" which pushes the whole set of nodes through the btTransform of the rigid body. This should output the global position of each of the nodes of a model, at any timestep. TO-DO: not sure if this should be tgNodes or just a vector of btVector3s.
  4. We could also provide a method that filters nodes based on a tgTagSearch. E.g., "getNodeGlobalPosition(tgTagSearch&)" that returns a list of nodes by tag.

One issue I'm already running into is passing around btVector3 objects as pointers to a vector of floats/doubles, since it seems to be overloaded that way, and since the simulator is smart enough to dynamically re-allocate memory from previous iterations, different data is stored in the same pointers. So I've got different tgModels with the "same" nodes, since only a pointer is stored. I'm going to need to be smarted about 'const', or maybe use copy constructors when passing tgNodes into a tgModel. Any advice here?

Do folks foresee any issues with dependencies? It makes me a bit concerned that we'll be including a class from tgcreator (tgNodes) in a tgModel, since I know we made a very conscious design decision to avoid that flow (creator knows about core, but core doesn't know about creator.)

Thanks all!

@apsabelhaus
Copy link
Member Author

Hello everyone, a quick update on this, particularly as applies to the current tgDataLogger2 infrastructure.

I checked and confirmed that different tgBaseRigids within the same compound rigid body point to the same btRigidBody. Example, I've got two vertebrae of a spine, each with 3 rods, and some debugging inside the tgCompoundRigidSensor constructor showed me the following:

Inside tgCompoundRigidSensor constructor, we have a set of tgBaseRigids and btRigidBodies with pointers:
tgBaseRigid pointer: 0xbca300 , btRigidBody pointer: 0xbd3a80
tgBaseRigid pointer: 0xbd3f30 , btRigidBody pointer: 0xbd3a80
tgBaseRigid pointer: 0xbc9730 , btRigidBody pointer: 0xbd3a80
Inside tgCompoundRigidSensor constructor, we have a set of tgBaseRigids and btRigidBodies with pointers:
tgBaseRigid pointer: 0xbd0950 , btRigidBody pointer: 0xbd34c0
tgBaseRigid pointer: 0xbb4f30 , btRigidBody pointer: 0xbd34c0
tgBaseRigid pointer: 0xbbba00 , btRigidBody pointer: 0xbd34c0

I'm adding this as a comment to the issue because it implies the following, which is missed at some points in the codebase:

  1. Querying a single rigid body within a compound gives the mass of the compound body, not the individual body
  2. Querying the XYZ position, or rotation, of a body within a compound gives that state of the compound, not the individual body

The implication here is that we will have different tgRodSensors recording data on the same rigid body. Users: be wary of this behavior, until we can provide an official debugging output/warning in the code.

If anyone has incentive to fix this please do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants