Let's see all the steps we need to create a plugin to use within ROS/IOP-Bridge. For this example we take an existing service which offers own functionality and also exports a library which is used by other services: urn:jaus:jss:environmentSensing:VisualSensor.
First of all we need an JSIDL which describes the service with all input/output messages and protocol behaviour. You find these definitions in the JAUS standard, in JAUS Toolset (GUI/resources/xml/.) or in fkie_iop_builder/jsidl/
. The definitions in fkie_iop_builder/jsidl/
are copies from JTS. The JSIDL files already used in plugins were modified to pass the received message as argument to the service handler:
<action name="accessControl.events.transport.Send"> --> <action name="sendReportVisualSensorCapabilities">
<argument value=" 'ReportVisualSensorCapabilities' "/> --> <argument value="msg"/>
<argument value="transportData"/>
</action>
Now we create a new ROS package (in our case fkie_iop_visual_sensor) which depends on roscpp
, fkie_iop_component
and fkie_iop_accesscontrol
. Each plugin should depend on fkie_iop_component
to get the funtionatlities of Bridge-Plugins and Builder-package. The fkie_iop_accesscontrol
package is included, because the VisualSensor inherits from AccessControl service. Our depends in package.xml looks now like:
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>fkie_iop_accesscontrol</build_depend>
<run_depend>roscpp</run_depend>
<run_depend>fkie_iop_accesscontrol</run_depend>
<run_depend>fkie_iop_component</run_depend>
In the next step we add JAUS services to CMakeLists.txt
:
iop_init(COMPONENT_ID 0)
iop_code_generator(
IDLS
urn.jaus.jss.core-v1.0/AccessControl.xml
urn.jaus.jss.core-v1.0/Events.xml
urn.jaus.jss.core-v1.0/Transport.xml
urn.jaus.jss.environmentSensing/VisualSensor.xml
OWN_IDLS
OVERRIDES
EXTERN_SERVICES
urn_jaus_jss_core_Events
urn_jaus_jss_core_AccessControl
urn_jaus_jss_core_Transport
GENERATED_SOURCES cppfiles
)
The call iop_init(COMPONENT_ID 0)
can stay for all plugins the same. In iop_code_generator::IDLS
we list all JAUS services included in this plugin. It is our service and all services in the inherit tree. The services we inherit from are already implemented in other packages and we want use them. To do this we add this services to iop_code_generator::EXTERN_SERVICES
. Thereby we use the directory name created by JTS for these services.
! internally our build script deletes all generated sources defined in
EXTERN_SERVICES
after creation by JTS.
Now we open a terminal and go to our package and run catkin build --this
. This generates in catkin_ws/build/fkie_iop_visual_sensor/jaus/Fkie_iop_visual_sensor_0
the source files for our service. In order to extend the functionality of the generated service, we copy the following files into our package, respecting the directory structure:
include/urn_jaus_jss_environmentSensing_VisualSensor/VisualSensor_ReceiveFSM.h
src/urn_jaus_jss_environmentSensing_VisualSensor/VisualSensor_ReceiveFSM.cpp
Additionally we create an empty file src/main.cpp
.
These files we add to iop_code_generator::OVERRIDES
in CMakeLists.txt
:
iop_code_generator(
:
OVERRIDES
include/urn_jaus_jss_environmentSensing_VisualSensor/VisualSensor_ReceiveFSM.h
src/urn_jaus_jss_environmentSensing_VisualSensor/VisualSensor_ReceiveFSM.cpp
src/main.cpp
:
)
Now we can implement the functionality for the service by extending the two files.
Additionally we have to add the plugin functionality! We have to create a plugin class inherited from iop::PluginInterface
which is localted at fkie_iop_component/iop_plugin_interface.h
. The plugin class should create an instance of our new JAUS service by providing the needed parameter to it. We create two files src/VisualSensorPlugin.h
and src/VisualSensorPlugin.cpp
with folling content:
#ifndef VISUALSENSORPLUGIN_H
#define VISUALSENSORPLUGIN_H
#include "urn_jaus_jss_environmentSensing_VisualSensor/VisualSensorService.h"
#include "urn_jaus_jss_core_AccessControl/AccessControlService.h"
#include "urn_jaus_jss_core_Events/EventsService.h"
#include "urn_jaus_jss_core_Transport/TransportService.h"
#include <fkie_iop_component/iop_plugin_interface.h>
namespace iop
{
class DllExport VisualSensorPlugin : public PluginInterface
{
public:
VisualSensorPlugin();
JTS::Service* get_service();
void create_service(JTS::JausRouter* jaus_router);
protected:
urn_jaus_jss_environmentSensing_VisualSensor::VisualSensorService *p_my_service;
urn_jaus_jss_core_AccessControl::AccessControlService *p_base_service;
urn_jaus_jss_core_Events::EventsService *p_events_service;
urn_jaus_jss_core_Transport::TransportService *p_transport_service;
};
};
#endif
#include <pluginlib/class_list_macros.h>
#include "VisualSensorPlugin.h"
using namespace iop;
using namespace urn_jaus_jss_environmentSensing_VisualSensor ;
using namespace urn_jaus_jss_core_AccessControl;
using namespace urn_jaus_jss_core_Events;
using namespace urn_jaus_jss_core_Transport;
VisualSensorPlugin::VisualSensorPlugin()
{
p_my_service = NULL;
p_base_service = NULL;
p_events_service = NULL;
p_transport_service = NULL;
}
JTS::Service* VisualSensorPlugin::get_service()
{
return p_my_service;
}
void VisualSensorPlugin::create_service(JTS::JausRouter* jaus_router)
{
p_base_service = static_cast<AccessControlService *>(get_base_service());
p_events_service = static_cast<EventsService *>(get_base_service(2));
p_transport_service = static_cast<TransportService *>(get_base_service(3));
p_my_service = new VisualSensorService(jaus_router, p_transport_service, p_events_service, p_base_service);
}
PLUGINLIB_EXPORT_CLASS(iop::VisualSensorPlugin, iop::PluginInterface)
Do not forget to add the .cpp file to the CMakeLists.txt
:
add_library(${PROJECT_NAME}
src/VisualSensorPlugin.cpp
${cppfiles}
)
Now we specify the IOP plugin description, so it can be found if we include it into our component. We create a new file plugin_iop.xml
in root of our package with follow content:
<library path="libfkie_iop_visual_sensor">
<class name="VisualSensor" type="iop::VisualSensorPlugin" base_class_type="iop::PluginInterface">
<description>
VisualSensor Service Plugin
</description>
<iop_service name="VisualSensor" id="urn:jaus:jss:environmentSensing:VisualSensor" version="1.0">
<inherits_from id="urn:jaus:jss:core:AccessControl" min_version="1.0"/>
</iop_service>
</class>
</library>
The values for iop_service tag are taken from JSIDL definition. The class tag describes our plugin and the class we created. For more details see Bridge-Plugins.
Then we include our plugin definition to the package.xml
:
<export>
<fkie_iop_component plugin="${prefix}/plugin_iop.xml" />
</export>
Now is the package.xml
done.
Set include directories:
include_directories(${catkin_INCLUDE_DIRS})
Add source files to the library:
add_library(${PROJECT_NAME} src/VisualSensorPlugin.cpp ${cppfiles})
Specify libraries to link a library against:
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})
The service of this package is used by other packages, like fkie_iop_digital_video or fkie_iop_still_image. So that catkin works properly we have to configure catkin_package
:
catkin_package(
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS fkie_iop_accesscontrol
)
If the package will be used as installed package we have to add install directives:
# Mark IOP include files for installation
install(
DIRECTORY ${IOP_INSTALL_INCLUDE_DIRS} DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
PATTERN "*.old" EXCLUDE
PATTERN "*.gen" EXCLUDE
)
# Mark executables and/or libraries for installation
install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
## Mark other files for installation (e.g. launch and bag files, etc.)
install(
FILES ./plugin_iop.xml
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
done! Build the package with catkin build fkie_iop_visual_sensor