Simbody
3.3
|
Construct a reasonably good spanning-tree-plus-constraints structure for modeling a given set of bodies and joints with a generalized coordinate multibody system like Simbody. More...
#include <MultibodyGraphMaker.h>
Classes | |
class | Body |
Local class that collects information about bodies. More... | |
class | Joint |
Local class that collects information about joints. More... | |
class | JointType |
Local class that defines the properties of a known joint type. More... | |
class | LoopConstraint |
Local class that represents one of the constraints that were added to close topological loops that were cut to form the spanning tree. More... | |
class | Mobilizer |
Local class that represents one of the mobilizers (tree joints) in the generated spanning tree. More... | |
Public Member Functions | |
MultibodyGraphMaker () | |
Construct an empty MultibodyGraphMaker object and set the default names for weld and free joints to "weld" and "free". More... | |
int | addJointType (const std::string &name, int numMobilities, bool haveGoodLoopJointAvailable=false, void *userRef=0) |
Specify relevant properties of a joint type. More... | |
void | addBody (const std::string &name, double mass, bool mustBeBaseBody, void *userRef=0) |
Add a new body (link) to the set of input bodies. More... | |
bool | deleteBody (const std::string &name) |
Delete a body (link) from the set of input bodies. More... | |
void | addJoint (const std::string &name, const std::string &type, const std::string &parentBodyName, const std::string &childBodyName, bool mustBeLoopJoint, void *userRef=0) |
Add a new joint to the set of input joints. More... | |
bool | deleteJoint (const std::string &name) |
Delete an existing joint from the set of input joints. More... | |
void | generateGraph () |
Generate a new multibody graph from the input data. More... | |
void | clearGraph () |
void | dumpGraph (std::ostream &out) const |
Output a text representation of the multibody graph for debugging. More... | |
int | getNumMobilizers () const |
Returns the number of mobilizers (tree joints) in the spanning tree. More... | |
const Mobilizer & | getMobilizer (int mobilizerNum) const |
Get a Mobilizer object by its mobilizer number, ordered outwards by topological distance from Ground. More... | |
int | getNumLoopConstraints () const |
Return the number of loop joint constraints that were used to close loops in the graph topology. More... | |
const LoopConstraint & | getLoopConstraint (int loopConstraintNum) const |
Get a loop constraint by its assigned number. More... | |
int | getNumBodies () const |
Return the number of bodies, including all input bodies, a ground body, and any slave bodies. More... | |
const Body & | getBody (int bodyNum) const |
Get a Body object by its assigned number. More... | |
int | getBodyNum (const std::string &bodyName) const |
Return the body number assigned to the input body with the given name. More... | |
int | getNumJoints () const |
Return the number of joints, including all input joints, and all joints added to connect otherwise disconnected bodies to Ground. More... | |
const Joint & | getJoint (int jointNum) const |
Get a Joint object by its assigned number. More... | |
int | getJointNum (const std::string &jointName) const |
Return the joint number assigned to the input joint with the given name. More... | |
int | getNumJointTypes () const |
Return the number of registered joint types. More... | |
const JointType & | getJointType (int jointTypeNum) const |
Get a JointType object by its assigned number. More... | |
int | getJointTypeNum (const std::string &jointTypeName) const |
Get the assigned number for a joint type from the type name. More... | |
void | setWeldJointTypeName (const std::string &name) |
Change the name to be used to identify the weld joint type (0 dof) and weld loop constraint type (6 constraints). More... | |
const std::string & | getWeldJointTypeName () const |
Return the name currently being used to identify the weld joint type and weld loop constraint type. More... | |
void | setFreeJointTypeName (const std::string &name) |
Change the name to be used to identify the free (6 dof) joint type and free (0 constraints) loop constraint type. More... | |
const std::string & | getFreeJointTypeName () const |
Return the name currently being used to identify the free joint type and free loop constraint type. More... | |
const std::string & | getGroundBodyName () const |
Return the name we recognize as that Ground (or World) body. More... | |
Construct a reasonably good spanning-tree-plus-constraints structure for modeling a given set of bodies and joints with a generalized coordinate multibody system like Simbody.
Each body has a unique name; each joint connects two distinct bodies with one designated as the "parent" body and the other the "child". We will output a spanning tree with Ground as the root, containing a mobilizer for every body. Each mobilizer corresponds to one of the joints from the input and has an "inboard" (topologically closer to Ground) and "outboard" (further from Ground) body, chosen from the parent and child bodies of the joint but possibly reordered in which case the mobilizer is marked as "reversed". Additional "free" mobilizers are added as needed between bodies and Ground so that there is a path from every body in the inboard direction all the way to Ground.
The output is
Then to build a multibody model
Normally every joint produces a corresponding mobilizer. A joint that would form a loop is marked as such, and then its child body is split to form a new "slave" body that can be mobilized by the joint. We expect that in the constructed multibody model, a master body and its slaves will be reconnected via weld constraints. This provides for uniform treatment of all joints, such as providing pin joint coordinates that can wrap. However, for some joint types that doesn't matter because the multibody system has equally good "loop joint" constraints. For example, Simbody's Ball mobilizer uses quaternions for orientation and hence has no wrapping; it can be replaced with a Ball constraint which removes the 3-dof mobilizer and 6 weld constraint equations, leaving just 3 translational constraints and indistinguishable behavior. Similarly a loop- closing Weld joint can just be replaced by a Weld constraint, and a loop- closing Free joint can simply be ignored.
The algorithm normally decides which joints are the loop-breakers, however you can specify in the input that certain joints must be loop joints.
Massless bodies can be very useful in defining compound joints, by composing pin and slider joints, for example. This is fine in an internal coordinate code as long as no massless (or inertialess) body is a terminal (most outboard) body in the spanning tree. Bodies can have a mass provided; if that mass is zero the algorithm will try to avoid ending any branch of the spanning tree there. If it fails, the resulting spanning tree is no good and an exception will be thrown. If no mass is provided we assume it is 1.
A body in the spanning tree that is directly connected to Ground is called a "base" body. If its mobilizer is a free joint then it can be given an arbitrary pose with respect to Ground and everything outboard of it moves together. This is a nice property and you can influence this choice by providing an explicit joint to Ground or designating some bodies as base bodies. Note that although you will then have a set of generalized coordinates permitting you to place these bodies arbitrarily, there is no guarantee that such placement will satisfy constraints. If you don't designate base bodies, the algorithm will pick them heuristically, which often leads to a good choice. The heuristic is to pick the body that has the most children but does not itself appear as a child. Failing that, pick the body that has the most children. In case of tie, pick the first body among the tied ones.
The first body you supply in the input will be interpreted as the Ground body. Its name will be used to recognize joints that connect other bodies to Ground. Typical names are "ground" or "world".
Each body in the spanning tree will be assigned a level, an integer that measures how many edges must be traversed to get from the body to Ground. Ground is at level 0, bodies that have a direct connection to Ground (base bodies) are at level 1, bodies whose mobilizer connects them to base bodies are at level 2, and so on. Multibody models need to be constructed in order of increasing level, so that the inboard body is already in the tree when the outboard body is added. We consider the level of a mobilizer to be the same as the level of its outboard body. Loop joints are not mobilizers and do not have a level.
SimTK::MultibodyGraphMaker::MultibodyGraphMaker | ( | ) |
Construct an empty MultibodyGraphMaker object and set the default names for weld and free joints to "weld" and "free".
int SimTK::MultibodyGraphMaker::addJointType | ( | const std::string & | name, |
int | numMobilities, | ||
bool | haveGoodLoopJointAvailable = false , |
||
void * | userRef = 0 |
||
) |
Specify relevant properties of a joint type.
Type name must be unique. Weld and free types are predefined and their names are reserved (though you can change the names to be used).
void SimTK::MultibodyGraphMaker::addBody | ( | const std::string & | name, |
double | mass, | ||
bool | mustBeBaseBody, | ||
void * | userRef = 0 |
||
) |
Add a new body (link) to the set of input bodies.
[in] | name | A unique string identifying this body. There are no other restrictions on the contents of name. Note that the Ground body is predefined and its name is reserved. |
[in] | mass | The mass here is used as a graph-building hint. If the body is massless, be sure to set mass=0 so that the algorithm will avoid making this a terminal body. The algorithm might also use mass to preferentially choose heavier bodies as terminal to improve conditioning. |
[in] | mustBeBaseBody | If you feel strongly that this body should be able to move freely with respect to Ground, set this flag so that the algorithm will connect it to Ground by a free joint before attempting to build the rest of the tree. Alternatively, provide a joint that connects this body directly to Ground, in which case you should not set this flag. |
[in] | userRef | This is a generic user reference pointer that is kept with the body and can be used by the caller to map back to his or her own data structure containing body information. |
bool SimTK::MultibodyGraphMaker::deleteBody | ( | const std::string & | name | ) |
Delete a body (link) from the set of input bodies.
All the joints that reference this body will be deleted too.
[in] | name | A unique string identifying this body. There are no other restrictions on the contents of name. Note that the Ground body is predefined and its name is reserved. |
true
if the body is succesfully deleted, false
if it didn't exist. void SimTK::MultibodyGraphMaker::addJoint | ( | const std::string & | name, |
const std::string & | type, | ||
const std::string & | parentBodyName, | ||
const std::string & | childBodyName, | ||
bool | mustBeLoopJoint, | ||
void * | userRef = 0 |
||
) |
Add a new joint to the set of input joints.
[in] | name | A string uniquely identifying this joint. There are no other restrictions on the contents of name. |
[in] | type | A string designating the type of this joint, such as "revolute" or "ball". This must be chosen from the set of joint types previously specified. |
[in] | parentBodyName | This must be the name of a body that was already specified in an earlier addBody() call, or it must be the designated name for the Ground body. If possible, this will be used as the inboard body for the corresponding mobilizer. |
[in] | childBodyName | This must be the name of a body that was already specified in an earlier addBody() call, or it must be the designated name for the Ground body. It must be distinct from parentBodyName. If possible, this will be used as the outboard body for the corresponding mobilizer. |
[in] | mustBeLoopJoint | If you feel strongly that this joint should be chosen as a loop joint, set this flag. In that case the joint will not appear in the list of joints that are candidates for mobilizers (tree joints). Only after the tree has been successfully built will this joint be added, either using a loop joint equivalent if one is available, or by splitting the child body into master and slave otherwise. In the latter case this joint will be made into a mobilizer but a loop weld joint will be added to attach the child slave body to its master. |
[in] | userRef | This is a generic user reference pointer that is kept with the joint and can be used by the caller to map back to his or her own data structure containing joint information. |
bool SimTK::MultibodyGraphMaker::deleteJoint | ( | const std::string & | name | ) |
Delete an existing joint from the set of input joints.
The bodies(links) referenced by the joint are expected to exist and their references to this joint will be removed as well.
[in] | name | A string uniquely identifying this joint. There are no other restrictions on the contents of name. |
true
if the joint is succesfully deleted, false
if it didn't exist. void SimTK::MultibodyGraphMaker::generateGraph | ( | ) |
Generate a new multibody graph from the input data.
Throws an std::exception if it fails, with a message in the what() string.
void SimTK::MultibodyGraphMaker::clearGraph | ( | ) |
void SimTK::MultibodyGraphMaker::dumpGraph | ( | std::ostream & | out | ) | const |
Output a text representation of the multibody graph for debugging.
|
inline |
Returns the number of mobilizers (tree joints) in the spanning tree.
These are numbered in order of level. The 0th mobilizer has level 0 and is just a placeholder for Ground's immobile connection to the universe. After that come the base mobilizers at level 1, then mobilizers that connect children to base bodies at level 2, and so on. This is also the number of mobilized bodies, including Ground and slave bodies.
|
inline |
Get a Mobilizer object by its mobilizer number, ordered outwards by topological distance from Ground.
|
inline |
Return the number of loop joint constraints that were used to close loops in the graph topology.
These do not include loops that were broken by cutting a body to make a slave body, just those where the joint itself was implemented using a constraint rather than a mobilizer plus a slave. The latter occurs only if were told there is a perfectly good loop joint constraint available; typically that applies for ball joints and not much else.
|
inline |
Get a loop constraint by its assigned number.
These are assigned in an arbitrary order.
|
inline |
Return the number of bodies, including all input bodies, a ground body, and any slave bodies.
|
inline |
Get a Body object by its assigned number.
These are assigned first to input bodies, then we add one for Ground, then we add slave bodies created by body splitting after that.
|
inline |
Return the body number assigned to the input body with the given name.
Returns -1 if the body name is not recognized. You can't look up by name slave bodies that were added by the graph-making algorithm.
|
inline |
Return the number of joints, including all input joints, and all joints added to connect otherwise disconnected bodies to Ground.
Don't confuse these with mobilizers, which are an ordered subset of the joints that are chosen to form a spanning tree connecting all the bodies.
|
inline |
Get a Joint object by its assigned number.
These are assigned first to input joints, then we add additional joints to Ground as needed.
|
inline |
Return the joint number assigned to the input joint with the given name.
Returns -1 if the joint name is not recognized. You can't look up by name extra joints that were added by the graph-making algorithm.
|
inline |
Return the number of registered joint types.
|
inline |
Get a JointType object by its assigned number.
|
inline |
Get the assigned number for a joint type from the type name.
|
inline |
Change the name to be used to identify the weld joint type (0 dof) and weld loop constraint type (6 constraints).
The default is "weld". Changing this name clears and reinitializes this MultibodyGraphMaker object.
|
inline |
Return the name currently being used to identify the weld joint type and weld loop constraint type.
|
inline |
Change the name to be used to identify the free (6 dof) joint type and free (0 constraints) loop constraint type.
The default is "free". Changing this name clears and reinitializes this MultibodyGraphMaker object.
|
inline |
Return the name currently being used to identify the free joint type and free loop constraint type.
const std::string& SimTK::MultibodyGraphMaker::getGroundBodyName | ( | ) | const |
Return the name we recognize as that Ground (or World) body.
This is the name that was provided in the first addBody() call.