8.0 KiB
Coding style for RBDL
This documents gives an overview of the coding style used in RBDL and also the general goals of RBDL.
If you are considering contributing to this library please read the whole document.
General Purpose of RBDL
RBDL implements large parts of the algorithms and methods described in Featherstone's book Rigid Body Dynamics Algorithms. One of the main goals of this library is to serve as an efficient implementation for the methods described in Featherstone's book and to a lesser extent general multibody dynamics and kinematics computations. A person who is familiar with Featherstone's book should have an easy time to understand the code and therefore the variable naming conventions used in the book should when possible used in the code, e.g.:
- the joint space inertia matrix is denoted with H
- the coriolis forces are denoted with C
The algorithmic parts of RBDL's code try to follow the algorithmic or mathematical notations instead of wrapping algorithms in elegant programming patterns.
Aims and Non-Aims of RBDL
This is what RBDL aims to be:
- RBDL aims to be lean
- RBDL aims to be easily integrated into other projects
- RBDL aims to be suitable as a foundation for sophisticated dynamics packages
- RBDL gives you access to its internals and provides only a thin abstraction layer over the actual computation
- RBDL aims to be self-contained and dependant on as few libraries as possible
And this is what RBDL is not about:
- RBDL is not a fully fledged simulator with collision detection or fancy graphics
- RBDL does not keep you from screwing up things.
Multibody dynamics is a complicated subject and in this codebase the preference is mathematical and algorithmic clarity over elegant software architecture.
Licensing
RBDL is published under the very permissive zlib license that gives you a lot of freedom in the use of full library or parts of it. The core part of the library is solely using this license but addons may use different licenses.
There is no formal contributor license agreement for this project. Instead when you submit patches or create a pull request it is assumed that you have the rights to transfer the corresponding code to the RBDL project and that you are okay that the code will be published as part of RBDL.
Data Storage
RBDL tries to avoid dynamic allocations and prefers contiguous memory
storage such as in std::vector
s over possibly fragmented memory as in
std::list
or heap allocated tree structures.
Where possible we use the Structure-of-Arrays (SOA) approach to store data,
e.g. the velocities v of all bodies is stored in an array (std::vector
)
of SpatialVector
s in the Model
structure.
Naming Conventions
- Structs and classes use CamelCase, e.g.
ConstraintSet
- Struct and class members use the lowerCamelCase convention, e.g.
Model::dofCount
. Exceptions are:- The member variable is a mathematical symbol in an
algorithm reference, E.g.
S
is commonly used to denote the joint motion subspace, then we use the algorithm notation. For mathematical symbols we also allow the underscore_
to denote a subscript. - Specializations of existing variables may be prefixed with an identifier,
followed by a underscore. E.g.
Model::S
is the default storage for joint motion subspaces, however for the specialized 3-DOF joints it uses the prefixmultdof3_
and are therefore stored inModel::multdof3_S
.
- The member variable is a mathematical symbol in an
algorithm reference, E.g.
- Only the first letter of an acronym is using a capital letter, e.g.
degree of freedom (DOF) would be used as
jointDofCount
, ordofCount
. - Variables that are not member variables use the
snake_case
convention.
Examples
struct Model {
std::vector<SpatialVector> v; // ok, v is an
std::vector<SpatialVector> S; // ok, S is commonly used in a reference algorithm
std::vector<double> u; // ok
std::vector<Vector3d> multdof3_u; // ok, 3-dof specialization of Model::u
std::vector<unsigned int> mJointIndex; // NOT OK: invalid prefix
unsigned int DOFCount; // NOT OK: only first letter of abbreviation should be in upper case
double error_tol; // NOT OK: use camelCase instead of snake_case
void CalcPositions(); // NOT OK: camelCase for member variables and function must start with lower-case name
};
Spacing and Line Width
We use spaces to indent code and use two spaces to indent a block. Do not use tabs. Namespaces should not be indented.
Lines should not exceed 80 characters in width.
Hint: in the root directory of the RBDL repository you find the file .editorconfig which uses the correct spacing settings automatically for many editors (see http://editorconfig.org/ for more details).
Error Handling
RBDL will fail loudly and abort if an error occurs. This allows you to spot errors early on. RBDL does not use exceptions.
Code must compile without warnings with all compiler warnings enabled. Please also consider checking code with static code analyzers such as clang-analyzer (http://clang-analyzer.llvm.org/).
Const Correctness
This code uses const correctness, i.e. parameters that are not expected to change must be specified as const. Use const references whenever possible. For some optional variables we use pointers, but when possible use references.
Braces
Use braces whenever possible. E.g. even there is only a single line of code
after an if-statement wrap it with curly braces. The opening brace starts
in the same line as the if
or the else
statement.
Documentation
Most importantly the code should be readable to someone who is familiar with multibody dynamics, especially with Featherstone's notation. The documentation should mainly serve to clarify the API in terms of doxygen comments. Within the code itself comments may be used to emphasize on ideas behind it or to clarify sections. But in general it is best to write readable code in the first place as comments easily become deprecated.
The doxygen comments should be written in the header files and not in the
.cc
files.
Testing
All code contributions must provide unit tests. RBDL uses UnitTest++ (https://github.com/unittest-cpp/unittest-cpp) as a testing framework. Many small tests that check single features are preferred over large tests that test multiple things simultaneously.
Bugfixes ideally come with a test case that reproduce the bug.
Branching and Bookmarks
RBDL uses Mercurial (https://mercurial-scm.org) as version control system. The branching concept of mercurial is different than in git. Git's branching concept is captured in mercurial using bookmarks (https://www.mercurial-scm.org/wiki/Bookmarks).
The default
branch is reserved for releases. Bugfixes and
contributions happen in the dev
branch but should have a bookmark
assigned to them.
Please do not create new branches, i.e. do not run hg branch <branchname>
.
Working on a new feature
The following steps are advised when working on a new feature for RBDL:
- Clone the official repository.
- Switch to the
dev
branch. - Create a bookmark that describes that feature preferably in a single word.
- Commit all changes to this bookmark in the
dev
branch. - Publish your work online and notify the RBDL maintainer(s).
Here are the commands to perform steps 1.-4.:
# Step 1: clone official repository
hg clone https://bitbucket.org/rbdl/rbdl <newfeature> && cd <newfeature>
# Step 2: switch to the dev branch
hg update dev
# Step 3: create a bookmark
hg bookmark newfeature
# ...
# Make changes
# ...
# Step 4: commit changes
hg commit
For step 5 the easiest would be to push your changes to a fork of the official repository on bitbucket and create a pull request.
Debugging
- Todo: mention logging facility
- Todo: mention SimpleMath as a fast-compiling (but slower runtime) linear algebra package.