The Deployment Component¶
Contents
Introduction¶
This document describes the Orocos OCL::DeploymentComponent
for
loading and configuring other components using an Orocos script or XML
file. This component can only load components into the same process.
Principle¶
Each Orocos component can be compiled as a shared, dynamic loadable library. Each such library can define a special function which will allow the DeploymentComponent to create new instances of a component type. This principle is analogous to the plugin mechanism found in web browsers or other desktop applications.
A common usage scenario of the DeploymentComponent goes as follows. An
initial Orocos application is created which contains only the
DeploymentComponent and the OCL::TaskBrowser
. When the application
is started, the TaskBrowser prompts for commands which can be given to
the DeploymentComponent.

Fig. 17 Component Deployment Overview¶
Fig. 17 shows the basic steps. An
XML file contains instructions for the DeploymentComponent where to look
for components (‘import statements’), which component types to create,
which name they must be given and how their internal thread is
configured (priorities, periods,…). Furthermore this file describes
the network interconnections between all components and how data must be
relayed from one component to another. The
loadComponents("file.xml")
method reads this file, looks up the
components, creates them and stores the configuration parameters. One
can apply the configuration (threads, properties, data connections,…)
by calling configureComponents()
. After this step, the components
(and the application as a whole) can be started with
startComponents()
. In order to do these steps at once, you can just
write kickStart("file.xml")
or in case of a script,
runScript("file.ops")
The configuration does not need to be stored in XML format. One can apply the same configuration by using the scripting methods of the DeploymentComponent at the console prompt, or by listing them in an Orocos script.
The Orocos Deployer Application¶
The Orocos Component Library provides a number of ready to use applications for loading and starting components using the DeployementComponent.
The main application is the deployer-<target>
program, where
<target> is replaced by the Operating System target (OROCOS_TARGET)
for which you want to load components, for example
deployer-gnulinux
. The program can take an optional argument
--start <filename>
which describes the components to load and is
used to kick-start the application. The XML and script specifications
are described below. When the application is started, the TaskBrowser is
presented to the user for receiving interactive commands. The name of
the DeploymentComponent is by default ‘Deployer’. In order to change
this name, use for example deployer-gnulinux NewDeployerName
. See
also deployer-<target> --help
for an overview of the options.
Note
In case you set the OROCOS_TARGET environment variable to the
target you want to use (for example “gnulinux”), you can also start
the deployer
command (which is a shell script), which will in
turn start the deployer-$OROCOS_TARGET
program. If no
OROCOS_TARGET has been set, it will refuse to start.
Similar scripts are available for rttscript
, cdeployer
,
ctaskbrowser
and deployer-corba
.
There are four related programs to the deployer application.
rttscript-<target>
: like above but does not show a TaskBrowser prompt. When it is finished deploying, it undeploys and quits. You’ll need to use a crafted .ops script to hold-off the quiting until your applications needs to. Useful for doing little tasks from the command line, unit tests or another script.cdeployer-<target>
: like above but starts the CORBA enabled non-interactive deployer application. You are not presented with a TaskBrowser prompt, but the cdeployer tries to connect to a CORBA Naming Service, and if that fails, prints the IOR to a file and to the screen.ctaskbrowser-<target> ComponentName|IOR
: Connects to a remote component (like the cdeployer above) using the CORBA IOR address or using the CORBA Naming Service using ComponentName.deployer-corba-<target>
: Combines the cdeployer and deployer applications. It presents the TaskBrowser console and sets up a CORBA server. It can thus be commanded locally and accessed over a network. If you quit the TaskBrowser prompt, the application exits.
The complete list of options for the deployer, cdeployer and deployer-corba programs are:
--help
Show program usage--start xml-or-script-file
(also -s) Deploy from an xml-file (.xml or .cpf) or script-file (.ops or .osd). This option may be given multiple times, in which case the xml and script files will be processed in the same order as on the command line.--log-level level
(also -l) Sets the Orocos log level to level. The level parameter should be one of: Never, Fatal, Critical, Error, Warning, Info, Debug, or Realtime. The parameter is case-insensitive. Warning: this overrides the ORO_LOGLEVEL environment variable.--no-consolelog
Turn off logging to the console (will still log to ‘orocos.log’)--daemon
(also -d) run the deployer as a background process. Will not open up a TaskBrowser prompt.--DeployerName deployer-name
Name of deployer component (the –DeployerName flag is optional)
Additionally, any CORBA options can be passed through these programs by adding a “–” command line option, followed by the CORBA-specific options.
Some examples are
deployer-corba --log-level warning -s myfile.xml
Sets the Orocos log level to warning
and deploys file myfile.xml
deployer-corba -l fatal --no-consolelog -s leftfile.xml LeftDeployer
Sets the Orocos log level to fatal
, turns off all logging to
console, names the deployer LeftDeployer
and deploys file
leftfile.xml
deployer-corba -l fatal --no-consolelog -s leftfile.xml LeftDeployer -- -ORBInitRef NameService=corbaloc:iiop:me.mine.home:2809/NameService -ORBFooBar 1
As with the previous example, and also passes some options through to the CORBA layer.
Configuration Procedure¶

Fig. 18 Deployment Procedure¶
The configuration format defines the instructions one can use to load and configure Orocos components. One can divide the instructions in three groups:
Where to look for component libraries and plugins
Which components to create and with which name
How each component is setup
Let’s demonstrate this principle with a simple application example as shown in Fig. 19. We want to setup an application with three components: a Reporting component, a ‘Controller’ and a ‘Plant’. The Plant component provides access to the hardware, the Controller component contains the control algorithm. The Reporting component is here to sense the values exchanged and write them to a file.
Fig. 19 Deployment Example Application¶
Where to look for component libraries¶
The path
and import
statements are the two ways to specify where
components can be found, and which component libraries to import.
Imagine that you have this directory structure:
/opt/robot : your orocos install path (lib, include, etc)
/opt/robot/lib/orocos/ : orocos installed components
/plugins : services and other plugins
/types : typekits and transports
And that you have a project ‘robot-13’ which is installed there as well,
but in a subdirectory of the /opt/robot/lib/orocos
directory:
/opt/robot/lib/orocos/robot-13 : robot-13 components
/robot-13/plugins : robot-13 services and other plugins
/robot-13/types : robot-13 typekits and transports
The RTT Plugins manual describes this typical directory structure more in detail.
The path
function extends the default search path with new
directories to look for components. In addition, it imports every
component library found in that directory, but without recursing into
sub directories. It does not cause any component to be created, but
allows the OCL::DeploymentComponent
to know where the component
libraries are located. This function may be called for multiple paths,
or provide them in a colon or semi-colon separated list.
In XML, the path statement looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<!-- .... -->
<!-- Note: capital 'P': -->
<simple name="Path" type="string"><value>/opt/robot/lib/orocos</value></simple>
</properties>
The script method equivalent is:
// note: small 'p':
path("/opt/robot/lib/orocos")
Each component library (.so, .dll,…) in the directory
/opt/robot/lib/orocos
is imported. If this directory contains a
plugins
or types
subdirectory, the libraries in these
directories are imported as well. Once you installed multiple component
libraries in subdirectories of your path, you must use the Import
statement to load these. In addition, when you use the ROS packaging
system, you can use Import
in order to load the components from a
ros package’s lib/orocos
directory, and all its dependencies. In
that case, only the ROS_PACKAGE_PATH environment variable needs to be
set.
In XML, the import statement looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<!-- .... -->
<!-- Note: capital 'I': -->
<simple name="Import" type="string"><value>robot-13</value></simple>
</properties>
The script method equivalent is:
// note: small 'i':
import("robot-13")
All component libraries found in <path>/robot-13
(or the ROS package
‘robot-13’) and their plugins/types are loaded because of this
statement. The import and path statements only allow you to load Orocos
plugin or component libraries. In case the import statement contains a
path to an existing library file, that file will be loaded directly
instead of looking it up in the search paths.
See the Plugin manual for creating plugin libraries or the end of this manual for creating component libraries. Regular libraries (like libfoo.so or win32.dll,…) can not be loaded. If a library contains one or more Orocos components, the contained component types become available in the next step.
To see the effects of the import function, the available types can be
queried by invoking the displayComponentTypes
(script) method:
(type 'ls' for context info) :displayComponentTypes()
Got :displayComponentTypes()
= I can create the following component types:
TaskContext
OCL::ConsoleReporting
OCL::FileReporting
OCL::HelloWorld
Robot13::Controller
Robot13::Diagnostics
(void)
Summarized:
path
pre-loads component libraries and sets the search path for subdirectoriesimport
loads component libraries from subdirectories in the search path OR a specific file directlydisplayComponentTypes
shows which components have been found.
Including other XML files¶
In order to manage your XML files, one XML file can include another with the ‘Include’ directive. The include directive may occur at any place in the XML file (but under <properties>) and will be processed as-if the included file is inserted at that point.
Warning
This option is new and experimental and may change in meaning and/or name in the future. When using the Xerces XML parser in Orocos, you may also want to use the standard XML way for including external documents, as documented on the Orocos Wiki.
In XML, the include statement looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<!-- .... -->
<simple name="Include" type="string"><value>default-imports.xml</value></simple>
<simple name="Include" type="string"><value>default-components.xml</value></simple>
</properties>
Which components to create and with which name¶
Import makes components available, but does not create an specific
instance yet. In order to add a component of a given type to the
current application, use the loadComponent
function:
In XML, the loadComponent statement of a reporting component would look like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<!-- ... import statements locate Orocos reporting library ... -->
<simple name="Import" type="string"><value>/usr/local/lib/orocos</value></simple>
<struct name="Reporter" type="OCL::FileReporting">
</struct>
</properties>
This line causes the DeploymentComponent to look up the OCL::FileReporting type, and if found, creates a component of that type with the name “Reporter”. This component is added as a peer component to the DeploymentComponent such that it becomes immediately available to the application. This step can be repeated any number of times with any number of components or names.
Alternatively, the type may be a filename if that file contains only one
component, which is exported using the ORO_CREATE_COMPONENT
macro
(see below).
The script method equivalent is:
loadComponent("Reporter", "OCL::FileReporting")
How each component is setup¶
Now that one or more component instances are created, you can configure them by connecting components, assigning threads, configuration values and program scripts. Again, you can do this using XML or the scripting language.
Below is an example of about all options you can use. They are explained in the sections below.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<simple name="Import" type="string"><value>/usr/local/lib/orocos</value></simple>
<!-- You can set per data flow connection policies -->
<struct name="SensorValuesConnection" type="ConnPolicy">
<!-- Type is 'shared data' or buffered: DATA: 0 , BUFFER: 1 -->
<simple name="type" type="short"><value>1</value></simple>
<!-- buffer size is 12 -->
<simple name="size" type="short"><value>12</value></simple>
</struct>
<!-- You can repeat this struct for each connection below ... -->
<struct name="Reporter" type="OCL::FileReporting">
<struct name="Activity" type="Activity">
<simple name="Period" type="double"><value>0.005</value></simple>
<simple name="Priority" type="short"><value>0</value></simple>
<simple name="Scheduler" type="string"><value>ORO_SCHED_OTHER</value></simple>
</struct>
<simple name="AutoConf" type="boolean"><value>1</value></simple>
<simple name="AutoSave" type="boolean"><value>1</value></simple>
<simple name="LoadProperties" type="string"><value>file-reporting.cpf</value></simple>
<struct name="Peers" type="PropertyBag">
<simple type="string"><value>Controller</value></simple>
</struct>
</struct>
<struct name="Controller" type="ControllerType">
<struct name="Activity" type="Activity">
<simple name="Period" type="double"><value>0.001</value></simple>
<simple name="Priority" type="short"><value>99</value></simple>
<simple name="Scheduler" type="string"><value>ORO_SCHED_RT</value></simple>
</struct>
<!-- loads the 'scripting' service (aka plugin) in this component -->
<simple name="Service" type="string"><value>scripting</value></simple>
<simple name="AutoConf" type="boolean"><value>1</value></simple>
<simple name="AutoStart" type="boolean"><value>1</value></simple>
<simple name="AutoConnect" type="boolean"><value>1</value></simple>
<!-- This section allows to define properties without using a file (see below)
These properties can be overriden in the property files below. -->
<struct name="Properties" type="PropertyBag">
<simple name="K" type="double"><value>1.0</value></simple>
</struct>
<!-- Note: difference between 'PropertyFile' and 'UpdateProperties' (see below) -->
<simple name="PropertyFile" type="string"><value>controller-main.cpf</value></simple>
<simple name="UpdateProperties" type="string"><value>controller-opts.cpf</value></simple>
<struct name="Ports" type="PropertyBag">
<!-- Note: the value is the name of the connection of which this port gets part.
All ports that share the same connection name are connected to each other
The connection policy for SensorValuesConnection was defined above. If no
policy is given, the default (DATA, LOCK_FREE) is used.
-->
<simple name="SensorValues" type="string"><value>SensorValuesConnection</value></simple>
<simple name="SteeringSignals" type="string"><value>DriveConnection</value></simple>
</struct>
<struct name="Peers" type="PropertyBag">
<simple type="string"><value>Plant</value></simple>
</struct>
<simple name="RunScript" type="string"><value>controller-program.ops</value></simple>
<simple name="RunScript" type="string"><value>controller-states.ops</value></simple>
</struct>
<struct name="Plant" type="PlantType">
<struct name="Activity" type="Activity">
<simple name="Priority" type="short"><value>0</value></simple>
<simple name="Scheduler" type="string"><value>ORO_SCHED_RT</value></simple>
</struct>
<simple name="AutoStart" type="boolean"><value>1</value></simple>
<struct name="Ports" type="PropertyBag">
<simple name="Position" type="string"><value>SensorValuesConnection</value></simple>
<simple name="Velocity" type="string"><value>DriveConnection</value></simple>
</struct>
</struct>
</properties>
Thread, period, priority and scheduler.¶
The first section of all three components sets up the active behaviour
of the component in the Activity
element.
<struct name="Activity" type="Activity">
<simple name="Period" type="double"><value>0.005</value></simple>
<simple name="Priority" type="short"><value>0</value></simple>
<simple name="Scheduler" type="string"><value>ORO_SCHED_OTHER</value></simple>
</struct>
Both have periodic activities, which run with a given period, priority
and in a scheduler. The Controller and Plant run in a real-time
scheduler, the Reporter doesn’t. The activities are created and attached
to each component during the configureComponents()
step of the
DeploymentComponent. Possible types of activities are
PeriodicActivity
,Activity
(the standard one),SequentialActivity
andSlaveActivity
.
The latter allows a component to be executed by a master component. You
can specify a master component using the Master
simple element in
the Activity
struct. The DeploymentComponent makes slaves
automatically a peer of their master, but does nothing more. Ie, the
code in the master’s updateHook() must call trigger on each of its
slaves that are peers.
Loading Services or Plugins.¶
You can load any number of plugins into a component. A plugin may also add a Service object to a component’s interface, but this is optional.
<!-- loads the 'scripting' service in this component -->
<simple name="Service" type="string"><value>scripting</value></simple>
<!-- loads the 'trajectory' plugin in this component -->
<simple name="Plugin" type="string"><value>trajectory</value></simple>
The Service
or Plugin
element may occur any number of times in
the component struct to list a specific service or plugin that must be
loaded in that component. For example, in order to execute a script in
your component, you may load the ‘scripting’ service. Or in order to
serialize its properties to XML, you’ll need the ‘marshalling’ service.
These services add new functions to your component which provide that
functionality.
A service promisses that it is available as a RTT::Service
object in
the component’s interface. A plugin doesn’t have this obligation, and
can have any desired effect on your component.
You can check the available services or plugins (ie discovered by the DeploymentComponent) with ‘.services’ or ‘.plugins’ and load a service from the TaskBrowser prompt in the current visited component with
.provide
<servicename>
. The Deployer has the equivalent function which looks like this:
loadService("Reporter","scripting")
Where Reporter must be a peer of the Deployer.
Auto-Configuration and Auto-Starting components.¶
The next section of the Controller contains the AutoConf
and
AutoStart
elements.
<simple name="AutoConf" type="boolean"><value>1</value></simple>
<simple name="AutoStart" type="boolean"><value>1</value></simple>
<simple name="AutoConnect" type="boolean"><value>1</value></simple>
If AutoConf
is set to 1, the DeploymentComponent will call the
component’s configure() method during configureComponents()
, after
the properties are loaded. If AutoStart
is set to 1, the component’s
start() method will be called during startComponents()
. By default
AutoConf
and AutoStart
are 0 (off).
There is no literal alternative for AutoConf in scripting. Just use the
configure()
operation of your component in order to configure it:
Controller.configure()
Controller.start()
Connecting Data Ports¶
The Ports
struct describes which ports of this component participate
in which data flow connection.
<struct name="Ports" type="PropertyBag">
<simple name="Position" type="string"><value>SensorValuesConnection</value></simple>
<simple name="Velocity" type="string"><value>DriveConnection</value></simple>
</struct>
So for each element in this struct, the name of the element is the port
name, and the value is the name of the connection it belongs to. Ports
with equal connection names are connected to each other. Ports which
are not listed will not be connected to anything. If ports of different
data types are being connected, the configuration phase will fail. You
can tune each connection using a struct of type ConnPolicy
with the
name of the connection. The allowed fields in this struct are the same
as in the C++ API, see RTT::ConnPolicy
.
<!-- You can set per data flow connection policies -->
<struct name="SensorValuesConnection" type="ConnPolicy">
<!-- Type is 'shared data' or buffered: DATA: 0 , BUFFER: 1 -->
<simple name="type" type="short"><value>1</value></simple>
<!-- buffer size is 12 -->
<simple name="size" type="short"><value>12</value></simple>
</struct>
<!-- You can repeat this struct for each connection below ... -->
In this example, the SensorValuesConnection is configured, which is used to connect the Controller’s SensorValues port with the Plant’s Position port.
Looking at the Ports section of the Controller above, it has two data
ports listed (SensorValues and SteeringSignals), which are added to two
connection objects. These connections show up in the Plant component’s
Ports
section as well. And it shows that the SensorValues Port is
connected to the Position Port and the SteeringSignals Port is connected
to the Velocity Port. If other component’s ports in the same file refer
to the same connection object, the ports are connected to each other by
the DeploymentComponent during the configureComponents()
step.
The AutoConnect
element indicates if the component’s data ports
should be automatically connected to peer ports which have the same name
and type. This flag is read during the configureComponents()
step of
the DeploymentComponent. Both components must have the AutoConnect
element set to 1 and one must be peer of the other in order to trigger
automatic connection of ports. It is possible that a port is connected
to one component using the Ports struct and to another component using
the AutoConnect
flag. If an automatic port connection fails, the
configuration procedure will not fail and just continue. An error
message may be logged. By default, AutoConnect
is 0 (off).
Note
AutoConnect is only useful for simple applications, use the explicit ‘Ports’ connection method to connect different named ports to each other !
In scripting, you can use the ConnPolicy
struct for connecting
ports. For example:
var ConnPolicy cp
cp.type = BUFFER
cp.size = 10 // buffer of size 10
connect("Plant.Position", "Controller.SensorValues", cp )
You may re-use the ‘cp’ object multiple times for different connections.
Streams can be created likewise, with the stream
operation of the
deployer, which only takes a port and a connection policy as argument.
Setting Properties (component parameters)¶
The Properties
struct allows to configure a component’s properties
from the main XML file. These values can be overridden by the listed
property files:
<!-- You can repeat this struct for each connection below ... -->
<struct name="Properties" type="PropertyBag">
<simple name="K" type="double"><value>1.0</value></simple>
</struct>
The PropertyFile
element specifies from which XML file each
component is configured and this file must contain values for all
properties of the component.
In case you only want to update part of the properties, use the
UpdateProperties
element.
<simple name="PropertyFile" type="string"><value>controller-main.cpf</value></simple>
<simple name="UpdateProperties" type="string"><value>controller-opts.cpf</value></simple>
Finally, it is also possible to load and create new properties from a
file using LoadProperties
the Reporting component requires this for
example:
<simple name="LoadProperties" type="string"><value>file-reporting.cpf</value></simple>
You can use any number or combination of these elements. The order is
respected. The properties are read during the configureComponents()
step of the DeploymentComponent. When the AutoSave
property is
turned on, the listed property file will be saved again with the values
of the Component, just before the Component is cleanup()
.
In scripting, you can use the marshalling
service in order to do the
property loading for you. For example:
loadService("MyComponent","marshalling")
MyComponent.marshalling.readProperties("file.cpf")
Every component that needs to read/write properties from a file needs the marshalling service. You can’t use the marshalling service of the Deployment Component, since that service would read/write the properties of the Deployment Component itself.
Setting up peer-to-peer relations¶
The last section of the Reporter component lists its peers.
<struct name="Peers" type="PropertyBag">
<simple type="string"><value>Controller</value></simple>
</struct>
The Reporter has one peer, the Controller, which allows the Reporter component to scan and use the interface of the Controller component. For example, it will discover which ports Controller exposes and be able to create connections to them, without the need of a supervisor to do so.
The Controller component has the Plant as peer, which means it can query and control it. For example, use its services, start and stop it etc.
Loading and Running Orocos Program Scripts¶
Note
This section is for starting scripts from the XML file. In case you want to use a script directly (or after an XML file), you can use the -s option of the deployer to let it execute that script.
The Controller has at the end two additional RunScript
elements
describing which script files must be loaded and executed into that
component.
<simple name="RunScript" type="string"><value>controller-program.ops</value></simple>
<simple name="RunScript" type="string"><value>controller-states.ops</value></simple>
Any number of scripts can be loaded and they are loaded in the order of
the XML file. Each script may contain any number of statements,
functions, program scripts or state machines. Running these scripts is
again done during the configureComponents()
step.
If you want to have a program or statemachine started you need to do so at the end of the script file itself, by adding
programname.start()
statemachine_instance.activate()
statemachine_instance.start()
statements. Be aware that this is done during the configuration phase of your components, so before updateHook() is executed. You are however allowed to start your component from the script by merely calling
start()
at the right place of your script.
You may choose to implement the whole deployment scenario in such a
script, instead of the XML file presented in this manual. In that case,
you need to load this script in the Deployer itself using the
-s filename.ops
command line option, or using a small XML file that
only contains this code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<struct name="Deployer" type="PropertyBag">
<!-- set a period -->
<struct name="Activity" type="Activity">
<simple name="Period" type="double"><value>0.01</value></simple>
</struct>
<!-- run a script -->
<simple name="RunScript" type="string"><value>scriptfile.ops</value></simple>
</struct>
</properties>
It is advised to set a period for the activity of a component executing scripts, since scripts need periodic execution in case they have to wait for an operation to complete. Alternatively, you can set the period at the top of your script file by adding the statement:
setPeriod(0.01)
instead of specifying it in the XML file.
CORBA extensions¶
The deployer XML format allows two CORBA specific boolean properties,
which are optional: Server
(defaults to ‘0’) and
UseNamingService
(defaults to ‘1’). These properties are only used
when you use the CORBA enabled cdeployer-<target>
or
deployer-corba-<target>
applications.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "cpf.dtd">
<properties>
<!-- ... -->
<struct name="Reporter" type="OCL::FileReporting">
<!-- CORBA specific extensions -->
<simple name="Server" type="boolean"><value>1</value></simple>
<simple name="UseNamingService" type="boolean"><value>1</value></simple>
</struct>
</properties>
By default, only the ‘Deployer’ starts as a CORBA server. You can have
other components to start as a server as well by setting the Server
property to 1. By default, the component will try to use the CORBA
Naming Service to register its name. If this is not wanted, set the
UseNamingService
property to 0.
The script method equivalent of the above XML construct is:
server("Reporter", true)
Which will create a CORBA server for the Reporter peer, after the Reporter was loaded with loadComponent().
Connecting to CORBA components¶
The corba enabled deployers allow to create a proxy for a remote component using the name service, the IOR or the IOR file.
Say you have a remote Orocos component with the name ‘MyComponent’. It
was created in one corba enabled deployer application with the
Server
property set to 1. You can connect to it from another
deployer application by using the XML syntax:
<!-- Uses CORBA Naming Service to lookup 'Mycomponent' -->
<struct name="MyComponent" type="CORBA">
</struct>
<!-- Uses IOR file to lookup 'Mycomponent' -->
<struct name="MyComponent.ior" type="IORFile">
</struct>
<!-- Uses literal IOR to lookup 'Mycomponent' -->
<struct name="IOR:...." type="IOR">
</struct>
Which will make this component available in your current application, using the same name as the original. This also works for the scripting deployer command ‘loadComponent’. For example, you can type in the TaskBrowser:
loadComponent("MyComponent", "CORBA")
loadComponent("MyComponent.ior", "IORFile")
loadComponent("IOR:.....", "IOR")
which allows to quickly connect to a remote component once you can copy/paste the IOR into the console.
Setting up a deployable component library¶
This section explains how to prepare a component library for deployment. It is demonstrated with an example.
Note
The orocreate-pkg
script of OCL does all the setup work for you.
This section is given for reference use only.
Additional Code¶
There exist three C macros for preparing a component library. The
simplest way is when the resulting library will contain only one
component type. Assume we have written the OCL::HelloWorld
component
( in the OCL C++ namespace) which is compiled in the
orocos-helloworld.so
library. The following code is added to
HelloWorld.cpp:
#include "HelloWorld.hpp"
#include <ocl/Component.hpp>
/* ... Hello World implementation file ... */
// You must specify the namespace:
ORO_CREATE_COMPONENT( OCL::HelloWorld )
This macro inserts a function into the library which will allow the DeploymentComponent to create OCL::HelloWorld components.
In case multiple components are defined in the same library, two other
macros must be used. One macro for each component type and one macro
once for the whole library. Say your library has components
NS::ComponentX
and NS::ComponentZ
in namespace NS. In order
to export both components, you could write in ComponentX.cpp
:
#include "ComponentX.hpp"
#include <ocl/Component.hpp>
/* ... ComponentX implementation file ... */
// once:
ORO_CREATE_COMPONENT_LIBRARY()
// For the ComponentX type:
ORO_LIST_COMPONENT_TYPE( NS::ComponentX )
and in ComponentY.cpp
the same but without the
ORO_CREATE_COMPONENT_LIBRARY macro:
#include "ComponentY.hpp"
#include <ocl/Component.hpp>
/* ... ComponentY implementation file ... */
// For the ComponentY type:
ORO_LIST_COMPONENT_TYPE( NS::ComponentY )
For each additional component in the same library, the ORO_LIST_COMPONENT_TYPE macro is added. It is allowed to put all the ORO_LIST_COMPONENT_TYPE macros in a single file.
Note
You may not link multiple libraries that use ORO_CREATE_COMPONENT, since only one of the component types will be found.
ORO_CREATE_COMPONENT_LIBRARY() replaces the pre-2.3.0 ORO_CREATE_COMPONENT_TYPE() macro. The old macro is still kept for backwards compatibility, both versions have the exact same result.
Compiling and linking a component library¶
In order to have a working library, care must be taken of the compilation flags. You may compile your library static or shared. But a static library will not be dynamically loadable. In the final executable the DeploymentComponent will be able to find the linked in components and setup the application using the XML file.
Important
The macros need some help to figure out if you are compiling a shared or static library. You need to define the RTT_COMPONENT macro (see below) when compiling for a shared library. If this macro is not defined, it is assumed that you are compiling for a static library.
The compilation flag of a component for a shared library might look like:
CFLAGS= -O2 -Wall -fPIC -DRTT_COMPONENT
LDFLAGS= -fPIC
The compilation flag of a component for a static library lacks both options :
CFLAGS= -O2 -Wall
LDFLAGS=
Note
If you use CMake with the UseOrocos.cmake macros, you don’t need any of this manual setup. The Orocos macros set the right flags for you.