Ignition Physics

API Reference

2.3.0
"Implement a custom feature"

Get the underlying dartsim world for this World object. public: dart::simulation::WorldPtr GetDartsimWorld(); };

Prerequisites

In the previous tutorial Installation, you have installed the Ignition Physics corresponding to the desired Ignition release.

Implement a custom feature in DART plugin

In the last Implement a physics plugin tutorial, we know how to implement a dummy physics engine as a plugin and load it using Ignition Physics API. In this tutorial, we will look deeper into the structure of a physics engine plugin, for example, the available DART physics engine in ign-physics repository and how to define a custom Feature for the plugin.

Folder structure of the plugins

Below is the general structure of the ign-physics repository:

ign-physics
├── dartsim Files for dartsim plugin component.
├── tpe Files for tpe plugin component.
├── include/ignition/physics Header files.
├── mesh Files for mesh component.
├── resources Model and mesh resource files used by tests.
├── sdf Files for sdf component.
├── src Source files and unit tests.
├── test
├── tutorials Tutorials, written in markdown.
├── Changelog.md Changelog.
└── CMakeLists.txt CMake build script.

As shown above, there are two physics engines available (more detail in Physics plugin tutorial):

  • DART: ignition-physics-dartsim-plugin.
  • TPE: ignition-physics-tpe-plugin.

and their plugin folders are placed just below the top level of ign-physics.

Looking closer to a plugin folder, for example, the dartsim (DART) plugin:

dartsim
├── worlds Example SDF files for testing dartsim plugin functionalities.
├── src Main implementation files of the plugin features interfacing the physics engines API
├── include/ignition/physics/dartsim Header files for the plugin features.
└── CMakeLists.txt CMake plugin build script.

Basically, new implementation of Feature or FeatureList, which is corresponded to a functionality of the external physics engine can be defined as a header in include/ignition/physics/<plugin_name> folder. The custom feature could be added in a FeatureList and implemented its functionalities in src folder.

The dartsim plugin's FeatureList could be found in Understanding the Physics Plugin tutorial.

Plugin and feature requirements

In general, the minimum set of features that any physics engine plugin must implement to be supported by Ignition Gazebo is as below:

This list defines the minimum requirements for the simulation capability of a physics engine plugin and also maintains backward compatibility with downstream physics plugins.

For custom feature requirements, there are two main component classes in the general structure of a custom feature:

  • Entity corresponds to the "proxy object" that the Feature is implemented. These are the most common "proxy objects" that are inherited from Entity class:

    • Engine: Placeholder class for the Engine API. This class serves metadata for the physics engine (for example the GetEngineInfo feature). Every Engine feature must inherit this class.
    • Joint: defines physics concept Joint behaviors (for example the GetBasicJointState feature).
    • Link: defines physics concept Link structure.
    • Model: defines physics concept Model structure (for example the GetLinkFromModel feature including both Link and Model objects).
    • Shape: defines physics concept Shape structure (for example the GetShapeKinematicProperties feature).
    • World: defines physics concept Shape structure (for example the RetrieveWorld feature in dartsim plugin).

    Note that these object classes are not mutually exclusive and could be defined in conjunction together to describe the Feature. There are also other uncommon objects defined depending on feature functionality, for example, the FreeGroup object in SetFreeGroupWorldPose feature. For more information about the physics concepts, please refer to Ignition Physics simulation concepts tutorial.

  • Implementation interfaces the actual physics engines API for the custom feature. It has InitiateEngine to trigger physics engine initiation to provide the required functionalities.

Moreover, we can define dependencies between custom Features:

  • By default, a blank feature will not require any other features. If the custom feature does require some other set of features, then it should be inherited from FeatureWithRequirements class, and provided a list of the Features required.
  • By default, a blank feature will not conflict with any other features. If the custom feature does conflict with some other set of features, then it should be inherited from FeatureWithConflicts class, and provided a list of the conflicting Features. The conflicting Features will not run at the same time when requested.

Define the custom feature

With the requirements and restrictions above, we will implement an example custom Feature that retrieves a simulation world from dartsim physics engine. For example, we name it as World.hh and the its content is as follow:

#include <dart/simulation/World.hpp>
namespace ignition {
namespace physics {
namespace dartsim {
class RetrieveWorld : public virtual Feature
{
public: template <typename PolicyT, typename FeaturesT>
class World : public virtual Feature::World<PolicyT, FeaturesT>
{
class Implementation : public virtual Feature::Implementation<PolicyT>
{
public: virtual dart::simulation::WorldPtr GetDartsimWorld(
const Identity &_worldID) = 0;
};
};
template <typename PolicyT, typename FeaturesT>
dart::simulation::WorldPtr RetrieveWorld::World<PolicyT, FeaturesT>
::GetDartsimWorld()
{
return this->template Interface<RetrieveWorld>()
->GetDartsimWorld(this->identity);
}
}
}
}

The new defined feature file is placed in dartsim/include/ignition/physics/dartsim:

dartsim
├── worlds
├── src
├── include/ignition/physics/dartsim
│ ├── World.hh
└── CMakeLists.txt

As seen above, after including the necessary library of dartsim and ign-physics, we define the RetrieveWorld custom feature inherited from the base Feature.

As defined, the RetrieveWorld feature retrieves world pointer from physics engine, so it is natural to define World entity inherited from Feature::World and declare the necessary member function GetDartsimWorld. Then we define the Implementation class having virtual member function for overriding in the actual implementation of the custom feature RetrieveWorld later.

Finally, we implement the World entity's member function GetDartsimWorld to call the Implementation class's member function GetDartsimWorld via Entity::Interface convenience function for querying the feature Implementation object.

Implement the custom feature

After defining the custom feature, please look into where it is added to a FeatureList in CustomFeatures.hh and implemented in CustomFeatures.cc. These files are place as follows:

dartsim
├── worlds
├── src
│ ├── CustomFeatures.hh
│ ├── CustomFeatures.cc
│ ├── ...
├── include/ignition/physics/dartsim
└── CMakeLists.txt

We display them here for convenience:

  • CustomFeatures.hh:
#include <ignition/physics/dartsim/World.hh>
#include "Base.hh"
namespace ignition {
namespace physics {
namespace dartsim {
using CustomFeatureList = FeatureList<
RetrieveWorld
>;
class CustomFeatures :
public virtual Base,
public virtual Implements3d<CustomFeatureList>
{
public: dart::simulation::WorldPtr GetDartsimWorld(
const Identity &_worldID) override;
};
}
}
}

The custom feature RetrieveWorld is added to CustomFeatureList, other custom features could also be added here. The CustomFeatures "FeatureList" here inherits from:

  • Base class for foundation definitions of Models, Joints, Links, and Shapes objects of dartsim interfacing to Ignition Physics API.
  • Implements3d for implementing the custom feature with FeaturePolicy3d ("FeaturePolicy" of 3 dimensions and scalar type double).

Based on the CustomFeatureList, we will override the corresponding member functions declared in each of the custom features. In this case, we have only the custom feature RetrieveWorld and its corresponding Implementation::GetDartsimWorld member function.

  • CustomFeatures.cc:
#include "CustomFeatures.hh"
namespace ignition {
namespace physics {
namespace dartsim {
dart::simulation::WorldPtr CustomFeatures::GetDartsimWorld(
const Identity &_worldID)
{
return this->worlds.at(_worldID);
}
}
}
}

Here we simply implement the actual behavior of GetDartsimWorld to return the world pointer from EntityStorage object storing world pointers of dartsim in Base class.

Finally, we add the implemented CustomFeatures "FeatureList" together with other FeatureList to final DartsimFeatures "FeatureList" as in dartsim/src/plugin.cc (please see Implement a physics plugin for registering the plugin to Ignition Physics).