dart icon indicating copy to clipboard operation
dart copied to clipboard

Most implementations of Shape::computeInertia do not account for their local transform

Open mxgrey opened this issue 10 years ago • 8 comments

Shapes are able to have a local transform within their Frame, but the computeInertia implementations of most Shape types do not account for that local transform. They should use coordinate transforms and the parallel axis theorem to shift the inertia matrices that they compute.

mxgrey avatar Mar 13 '15 05:03 mxgrey

Shape can use math::transformInertia() to transform the inertia. Actually, math::transformInertia() is for transforming spatial inertia (6x6 version of inertia that contains inertia and mass together) but I think Shape should provide spatial inertia. Since Shape can compute its volume, it can compute inertia and mass with density.

The only use case of Shape's inertia is to help setting BodyNode's inertia when it's not provided in skel file. I think there are two problems there.

~~(a) The inertia and mass of BodyNode would be inconsistent since BodyNode gets inertia only from Shape.~~ Edit: Shape computes inertia given mass. (b) BodyNode doesn't account multiple Shapes.

So (i) Shape should provide inertia and mass at the same time, and (ii) BodyNode should have API that can compute its total mass and inertia from the visualization shapes.

jslee02 avatar Mar 13 '15 06:03 jslee02

I went ahead and created a function called math::parallelAxisTheorem(const Matrix3d&, const Vector3d&, double) which will shift a moment of inertia matrix according to the classical parallel axis theorem. I created it for the LineSegmentShape::computeInertia pertaining to #346.

I'm thinking about creating a pull request that includes both my LineSegmentShape implementation and also fixes this current issue (because now that the parallelAxisTheorem function exists, fixing this issue is trivial). Let me know if you'd prefer me to split up those pull requests.

mxgrey avatar Mar 13 '15 07:03 mxgrey

I'm thinking about creating a pull request that includes both my LineSegmentShape implementation and also fixes this current issue (because now that the parallelAxisTheorem function exists, fixing this issue is trivial). Let me know if you'd prefer me to split up those pull requests.

I think separate pull requests would make it easier to merge LineSegmentShape first.

jslee02 avatar Mar 13 '15 07:03 jslee02

The information required by BodyNode to compute spatial inertia is mass, local inertia, and local transformation of the Shape. Providing transformed inertia is optional. One BodyNode can get the information from each Shape, transforming can be done in BodyNode.

So I prefer Shape to have member functions like:

class Shape : public Frame
{
public:
  // This is in Frame
  // virtual Isometry3d getRelativeTransform();

  virtual Matrix3d computeLocalInertia(double _density) = 0;

  double computeMass(double _density) 
  { return _density * computeVolume(); }

  Matrix3d computeInertiaFromMass(double _mass)
  { return computeLocalInertia(_mass / computeVolume()); }

  // Optional
  Matrix3d getTransformedInertia();
  Matrix6d getTransformedSpatialInertia();

protected:
  virtual double computeVolume() = 0;
};

jslee02 avatar Mar 13 '15 07:03 jslee02

I think that sounds reasonable, although getTransformedInertia() and getTransformedSpatialInertia() will both require knowledge of mass. So either we need to store mass in the shape, or we need to pass mass as an argument to them.

mxgrey avatar Mar 13 '15 07:03 mxgrey

I think passing either mass or density more make sense. Shape just contains geometric data and provides utility functions computing inertia (and mass) with its geometric data and given mass or density.

jslee02 avatar Mar 13 '15 07:03 jslee02

With the upcoming ShapeNode #394 changes, I think the responsibility of transforming the spatial inertia needs to fall on the ShapeNode instead of the Shape, because the Shape will no longer be aware of its local transform; that will be the job of the ShapeNode. So Shape will offer the computeLocalInertia function while ShapeNode will offer the computeTransformedInertia functions.

On another note, something that occurred to me recently is that there's some ambiguity over whether an object would be solid or hollow. The inertia of a solid object is very different than the inertia of a hollow object with the same geometry. I'm thinking we could offer something like:

enum ShapeFill {
  SOLID=0,
  SURFACE
};

Shape::computeMass(double density, ShapeFill fill = SOLID, double thickness = 0.0)
Shape::computeLocalInertia(double density, ShapeFill fill = SOLID, double thickness = 0.0)

The enumeration will distinguish between whether the shape should compute the properties based on a solid object or a hollow object with a specified thickness. If the object is solid, then the thickness parameter is ignored. Alternatively we could do this:

Shape::computeMass(double density)
Shape::computeSurfaceMass(double density, double thickness)
Shape::computeLocalInertia(double density)
Shape::computeLocalSurfaceInertia(double density, double thickness)

But I would prefer if it were possible for a user to programmatically switch between solid and hollow without much difficulty.

mxgrey avatar Jul 03 '15 23:07 mxgrey

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 13 '18 19:02 stale[bot]