-
Notifications
You must be signed in to change notification settings - Fork 28
Tutorial | Creating a Plugin
Writing a new plugin can be broken down into a few basic steps; writing the core of your plugin, adding your plugin to the base project CMakeList, the add a callback and config for your plugin into the main omnimapper ros wrapper. Ascertaining good understating of the overall working of the project through reading ICRA publication would be wise before attempting to modify the code.
Before we get started on writing a new plugin, lets get acquainted with the structure of the project's source. I'f you've followed the installation guide or have looked through the CMake files, then the directories should be familiar. The root source folder contains several directories:
-
base
is the source folder for the base framework for OmniMapper -
doc
has the used Doxyfile files -
plugins
is the source folder we'll add our plugins to -
ros
containsomnimapper_ros
, the ros wrapper for OmniMapper, as well as other3rdparty
dependencies
The following files are what you'll need to modify to get started:
-
foo.h
,foo.cpp
your new plugin class within the plugin folder -
CMakeLists.txt
for the base project is where to include your new plugin files -
omnimapper_ros.h
,omnimapper_ros.cpp
in the main files for the wrapper nodes.
As a side note, our lab has made efforts to keep the base code for OmniMapper ROS independent, thus the purpose of authoring plugins within the base to help maintain this. There are some plugins however that are quite too interdependent or have not been ported to exist outside of the ros wrapper, including the Canonical Scan Matching or Visualization plugins. The ICP plugin however shows how to avoiding ROS dependencies and will serve as good example within this tutorial.
###Plugin Base
Depending on utility of your plugin, you'll most likely want to include omnimapper/trigger.h
used when enabling your plugin's callback, omnimapper/get_transform_functor.h
used for resolving sensor transforms within the global reference frame, as well as any gtsam
header required for your application. As an general example, if you happen to be developing a plugin utilizing 3D point based landmarks, you'll mostly require gtsam/geometry/Point3.h
and gtsam/geometry/Pose3.h
to generate the landmark and robot symbols as well as gtsam/nonlinear/Symbol.h
and gtsam/slam/BetweenFactor.h
to handle and generate factors to bind the symbols using observed measurements. If the reader is unfamiliar with GTSAM and factor based approaches, an encouraged reading would be Factor Graphs and GTSAM: A Hands-on Introduction by Frank Dellaert, Technical Report GT-RIM-CP&R-2012-002. See icp_plugin.h for a working example.
In your plugin, you'll want to declare several standard plugin functions as well as a few class verbals. These are:
-
void spin ();
Spin starts a thread spinning, which will process new data as it becomes avalable. This is the function you'll use to thread your plugin when starting the ros wrapper node. -
void fooCallback (const MyDataPtr& data);
You'll need a callback function to allow OmniMapper node to share new data as its published. You'll most likely want to put a mutex on the variable used to share the incoming data between the callback and the spin function. -
bool ready ();
A function that allows OmniMapper to inquire about the plugins current state for processing new data. -
void setFoo(datatype data)
You'll want a way to setup your plugin upon initialization, this is done by adding ros param functions to the ros wrapper that will parse setting from the launch file and then in turn call your plugin's set functions. A good idea is to keep a consistent naming across, from launch file, to wrapper to plugin calls, to plugin variables. -
void reset ();
A method OmniMapper can reset the plugin if requested. Some important variables are: -
OmniMapperBase* mapper_;
this is a object your using to interface with the base of OmniMapper for fundamental tasks such as requesting for an optimized pose symbol to adding a new factor the graph. -
GetTransformFunctorPtr get_sensor_to_base_;
this is the object you'll use to gather sensor transforms from subscribed sensors.
In the .cpp should maintain the morality of your plugin's code, while not forgetting to include your plugin's header file as well as omnimapper/omnimapper_base.h
. See icp_plugin.cpp for another detailed example. You'll then want to modify the base project's CMakeLists.txt to include your new source files accordingly.
Currently the ros wrapper is a bit messy and monolithic, but in the omnimapper_ros.h and omnimapper_ros.cpp files, the primary things will need to are:
1 Import our plugin's header files
2 Define an object instance of our plugin class
3 Add the set functions for out plugin in the loadROSParams() subroutine
4 Add a wrapper callback used for any data conversion or prepossessing before exiting the ROS namespace
5 Subscribe our our plugin's sensor_to_base and wrapper callback to the desired messages topics
6 Start a boost::thread using the plugin's spin function