dartsim / dart

DART: Dynamic Animation and Robotics Toolkit
http://dartsim.github.io/
BSD 2-Clause "Simplified" License
884 stars 286 forks source link

Proposal: Implement WeldJoint::merge() function #1009

Open junhyeokahn opened 6 years ago

junhyeokahn commented 6 years ago

Hello, I have a small questions on how dart handles fixed joint. I realized several of dynamics libraries (e.g. RBDL) just connect fixed link to its parent's link and handle as a one combined link by adjusting mechanical properties. For example, if the tree structure seems, j1 -- l1 -- j2 -- l2 where j2 is fixed joint, RBDL just removes j2 and handle both link together l_new = (l1+l2) : j1 -- l_new. Also, every mechanical properties are adjusted as well. For example, when I require the mass property, it returns m_new = m1+m2, and so on.

I am not sure if it is general way to handle multibody object including fixed joints, but does dart handle fixed joints as similar to above? If so, where does dart trace them? I found DegreeOfFreedom::getChildBodyNode(), but it only returns the exact child body node regardless of the next joint type of child node.

I think in the case of computing properties which require iterative process through every BodyNodes (e.g. centroid dynamics property), aforementioned schemes could show some efficiency.

mxgrey commented 6 years ago

DART treats all joints as joints, including fixed joints. If DART is told that something is a joint, it will be a joint. In the case of a fixed joint, it's a Joint with no degrees of freedom which constrains two bodies to be rigidly attached to each other.

If someone wants an efficiency improvement by merging two bodies that are connected by a fixed joint, they are welcome to do so by either modifying their model file (.urdf, .sdf, or .skel) or by modifying the Skeleton programmatically (you can change joint types and body properties at runtime through the DART API, which includes deleting Joints and BodyNodes).

To understand why we refuse to use the technique you've described, it would be impertinent of us to change the number of joints or the number of bodies to be different than the model that a user explicitly loaded. Imagine someone's confusion if they ask for 6 bodies, but we only give them 5. Or they end up with one fewer joint than they requested.

There are any number of reasons that a user might specify two bodies connected by a fixed joint instead of one body. Maybe they want to be able to adjust the inertia properties of the two bodies independently of each other. Maybe they want to use each body as a separate frame of reference.

If a user actually wants one body instead of two, they are welcome to create a model that specifies one body instead of two. That's not for us to decide.

Granted, sometimes a fixed joint is used for convenience when writing a model file, and the user doesn't actually care about having the final number of bodies and joints match the original specification. We could consider putting an optional element in the skel format for WeldJoint, maybe called something like <merge> which would explicitly tell the parser to merge the two bodies together. We might also be able to add that sort of element to our sdf parser, and maybe the urdf parser.

That seems like a very low priority feature, though, since I expect it will mostly just live in obscurity.

mxgrey commented 6 years ago

I guess we could even give the WeldJoint itself a function like WeldJoint::merge() which would remove the WeldJoint and child body, connect the child of the child to the parent, and modify the parent to have the physical properties of both bodies combined. We'd also have to move any Nodes (e.g. ShapeNode, EndEffector, custom user nodes) from the child to the parent; that would probably be the trickiest part.

junhyeokahn commented 6 years ago

Thanks for the kind explanation on the philosophy underneath. I definitely agree on what you described. Also, WeldJoint::merge() sounds great feature if the trickiest part could be well enough handled.