Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tutorial implement a physics plugin #128

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tutorials.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Ignition @IGN_DESIGNATION_CAP@ library and how to use the library effectively.
3. \subpage physicsplugin "Understanding the Physics Plugin"
4. \subpage switchphysicsengines "Switching physics engines"


7. \subpage createphysicsplugin "Implement a physics plugin"

## License

The code associated with this documentation is licensed under an [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0).
Expand Down
174 changes: 174 additions & 0 deletions tutorials/07-implementing-a-physics-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
\page createphysicsplugin "Implement a physics plugin"

This tutorial guides how to develop a simple plugin that implements a 3D policy
and includes a sample list of Features.

## Prerequisites

In the previous tutorial \ref installation "Installation", you have installed the
Ignition Physics corresponding to the desired Ignition release. Note that the
recommended Ignition release is Dome.

## Write a simple physics plugin

Please create a folder for the plugin first:

```bash
cd ~
mkdir -p ~/simple_plugin/build
cd simple_plugin
```

Then download the example loader into your current directory by:

```bash
wget https://raw.githubusercontent.com/ignitionrobotics/ign-physics/main/examples/hello_world_plugin/HelloWorldPlugin.cc
```

### Examine the code

We first include these:
- \ref ignition::physics::FeatureList "FeatureList" header: to define a list of
\ref ignition::physics::Feature "Feature" that will be implemented for the
plugin, e.g. \ref ignition::physics::GetEngineInfo "GetEngineInfo".
- \ref ignition::physics::FeaturePolicy "FeaturePolicy" header: to specify the
metadata about the coordinate system (e.g. 2 or 3 dimensions) and numeric system
(e.g. float, int) that the `Features` will be implemented accordingly.
- `GetEntities.hh` header: to retrieve the pre-defined list of features in
Ignition Physics. Please refer to this [API Reference](https://ignitionrobotics.org/api/physics/3.0/GetEntities_8hh.html)
for a list of features defined in `GetEntities.hh` and \ref physicsplugin
"Understanding the Physics Plugin" tutorial for an example list of common features
implemented with a plugin.
- `Register.hh` header: to register a plugin to Ignition Physics.

```cpp
#include <ignition/physics/FeatureList.hh>
#include <ignition/physics/FeaturePolicy.hh>
#include <ignition/physics/GetEntities.hh>
#include <ignition/physics/Register.hh>
```

Next, let us define a namespace `mock` and implement our plugin in it.
We will add a pre-defined feature `GetEngineInfo` to our plugin's
`HelloWorldFeatureList` as follow:

```cpp
struct HelloWorldFeatureList : ignition::physics::FeatureList<
ignition::physics::GetEngineInfo
> { };
```

The plugin will be able to return its physics engine metadata.
We will now implement our plugin class named `HelloWorldPlugin`
using the defined `FeatureList` above. The class is inherited from
\ref ignition::physics::Implements3d "Implements3d" to declare that our plugin's
`HelloWorldFeatureList` will be in the 3D coordinate system.

```cpp
class HelloWorldPlugin
: public ignition::physics::Implements3d<HelloWorldFeatureList>
{
using Identity = ignition::physics::Identity;

public: Identity InitiateEngine(std::size_t /*_engineID*/) override
{
this->engineName = "HelloWorld";

return this->GenerateIdentity(0);
}

public: std::size_t GetEngineIndex(const Identity &/*_id*/) const override
{
return 0;
}

public: const std::string &GetEngineName(const Identity &/*_id*/) const override
{
return this->engineName;
}

std::string engineName;
};
```

For now, because we do not have any real physics engines, we will define a dummy
physics engines inside member function `InitiateEngine` by simply setting
```cpp
this->engineName = "HelloWorld"
```
and returning the engine object using \ref ignition::physics::Identity. Then, we
define the metadata getters `GetEngineIndex` and `GetEngineName` for our plugin
and that's it.

Finally, we only have to register our plugin in Ignition Physics as a physics
engine by:

```cpp
IGN_PHYSICS_ADD_PLUGIN(
HelloWorldPlugin,
ignition::physics::FeaturePolicy3d,
HelloWorldFeatureList)
```
Note that:
- The first argument is the name of the class that wraps the physics engine into
a plugin.
- The second argument is the `FeaturePolicy` for this plugin, i.e. `FeaturePolicy3d`
- The third argument is the `FeatureList`, specifying all the features that this
plugin provides, i.e. `HelloWorldFeatureList`

### Setup CMakeLists.txt for building (Dome release)

Now create a file named `CMakeLists.txt` with your favorite editor and add these
lines for finding `ign-plugin` and `ign-physics` dependencies for Dome release:

```cmake
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
set(IGN_PLUGIN_VER 1)
find_package(ignition-plugin${IGN_PLUGIN_VER} 1.1 REQUIRED COMPONENTS all)
set(IGN_PHYSICS_VER 3)
find_package(ignition-physics${IGN_PHYSICS_VER} REQUIRED)
```

After that, add the executable pointing to our plugin file and add linking
library so that `cmake` can compile it:

```cmake
add_library(HelloWorldPlugin SHARED HelloWorldPlugin.cc)
target_link_libraries(HelloWorldPlugin
PRIVATE
ignition-physics${IGN_PHYSICS_VER}::ignition-physics${IGN_PHYSICS_VER})
```

## Build and run

### Compile the plugin

Now you can build the plugin by:

```bash
cd build
cmake ..
make
```

This will generate the `HelloWorldPlugin` library under `build`.
The exact name of the library file depends on the operating system
such as `libHelloWorldPlugin.so` on Linux, `libHelloWorldPlugin.dylib` on macOS,
and `HelloWorldPlugin.dll` on Windows.

### Test loading the plugin on Linux

Please first follow the \ref pluginloading "Loading a Physics Plugin" tutorial
to create a simple loader. Then we test our plugin using the loader as follow:

```bash
cd ~
./simple_loader/build/hello_world_loader simple_plugin/build/libHelloWorldPlugin.so
```

And you will see the engine info of our plugin:

```bash
Testing plugin: mock::HelloWorldPlugin
engine name: HelloWorld
```