- Development
- European Robotics Forum 2011 Workshop on the Orocos Toolchain
- European Robotics Forum 2012: workshops
- Geometric relations semantics
- KDL wiki
- Kuka LBR user group
- Links of Orocos components
- OCL v1.x wiki
- RTT v1.x wiki
- Toolchain v2.x
- Wiki for site admins
- iTaSC wiki
Name connections, not ports (aka Orocos' best kept secret)
Table of Contents
Rationale
Problem: How to reuse a component when you need the ports to have different names?
Solution: Name the connection between ports in the deployer. This essentially allows you to rename ports. Unfortunately, this extremely useful feature is not documented anywhere (as of July, 2009). <!-- break -->
Assumptions
- The build directory is within the source directory. Click below to read the rest of this post.== Rationale ==
Problem: How to reuse a component when you need the ports to have different names?
Solution: Name the connection between ports in the deployer. This essentially allows you to rename ports. Unfortunately, this extremely useful feature is not documented anywhere (as of July, 2009). <!-- break -->
Assumptions
- The build directory is within the source directory. This helps with dynamic library loading.
- Admittedly, this is contrived example but the structure is very useful and occurs more frequently than you may realise (say using N copies of a camera component, deploying components for both a left and a right robot arm within the same deployer, etc).
Files
Example overview
This example occurs in three parts
- A Human-Machine-Interface (HMI) component connects to a Robot component, and provides a desired cartesian position.
- A one-axis filter is placed between the HMI and Robot component, to zero out one axis (say, you did not want the robot to move in one direction due to an obstacle or something similar)
- A second one-axis filter is placed between the first filter and the Robot. The two filters are the exact same component with the same named ports.
Components
class HMI : public RTT::TaskContext { protected: // *** OUTPUTS *** /// desired cartesian position RTT::WriteDataPort<KDL::Frame> cartesianPosition_desi_port; public: HMI(std::string name); virtual ~HMI(); protected: /// set the desired cartesian position to an initial value /// \return true virtual bool startHook(); };
class Robot : public RTT::TaskContext { protected: // *** INPUTS *** /// desired cartesian position RTT::ReadDataPort<KDL::Frame> cartesianPosition_desi_port; public: Robot(std::string name); virtual ~Robot(); };
class OneAxisFilter : public RTT::TaskContext { protected: // *** INPUTS *** /// desired cartesian position RTT::ReadDataPort<KDL::Frame> inputPosition_port; // *** OUTPUTS *** /// desired cartesian position RTT::WriteDataPort<KDL::Frame> outputPosition_port; // *** CONFIGURATION *** /// specify which axis to filter (should be one of "x", "y", or "z") RTT::Property<std::string> axis_prop; public: OneAxisFilter(std::string name); virtual ~OneAxisFilter(); protected: /// validate axis_prop value /// \return true if axis_prop value is valid, otherwise false virtual bool configureHook(); /// filter one translational axis (as specified by axis_prop) virtual void updateHook(); };
Component implementation
The component implementations are not given in this example, as they are not the interesting part of the solution, but are available in the Files section above.
The interesting part is in the deployment files ...
Deployment
Part 1: HMI and Robot
This part simply connects the HMI and robot together (see deployment file Connect-1.xml).
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "cpf.dtd"> <properties> <simple name="Import" type="string"> <value>liborocos-rtt</value> </simple> <simple name="Import" type="string"> <value>liborocos-kdl</value> </simple> <simple name="Import" type="string"> <value>liborocos-kdltk</value> </simple> <simple name="Import" type="string"> <value>libConnectionNaming</value> </simple>
<struct name="HMI" type="HMI"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>cartesianPosition_desi</value></simple> </struct> </struct>
<simple name="portName" type="string"> <value>connectionName</value> </simple>
<struct name="Robot" type="Robot"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>HMI</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>cartesianPosition_desi</value></simple> </struct> </struct> </properties>
Now, the deployer uses connection names when connecting components between peers, not port names. So it attempts to connect a Robot.cartesianPosition_desi connection to a Vehicle. cartesianPosition_desi connection (which in this part, matches the port names).
Build the library, and then run this part with
cd /path/to/ConnectionNaming/build deployer-macosx -s ../Connect-1.xml
Examine the HMI and Robot components, and note that each has a connected port, and the port values match.
Part 2: HMI, one filter and a robot
This part adds a filter component between the HMI and the robot (see Connect-2.xml)
As with Part 1, the first part of the file loads the appropriate libraries (left out here, as it is identical to Part 1).
<struct name="HMI" type="HMI"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>unfiltered_cartesianPosition_desi</value></simple> </struct> </struct>
<struct name="Filter" type="OneAxisFilter"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>HMI</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="inputPosition" type="string"> <value>unfiltered_cartesianPosition_desi</value></simple> <simple name="outputPosition" type="string"> <value>filtered_cartesianPosition_desi</value></simple> </struct> <simple name="PropertyFile" type="string"> <value>../Filter1.cpf</value></simple> </struct>
<struct name="Robot" type="Robot"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>Filter</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>filtered_cartesianPosition_desi</value></simple> </struct> </struct>
Run this part with
cd /path/to/ConnectionNaming/build deployer-macosx -s ../Connect-2.xml
Examine all three components, and note that all ports are connected, and in particular, that the HMI and Filter.inputPosition ports match while the Filter.outputPosition and Vehicle ports match (ie they have the 'x' axis filtered out).
Using connection naming allows us to connect ports of different names. This is particularly useful with a generic component like this filter, as in one deployment it may connect to a component with ports named cartesianPosition_desi, while in another deployment it may connect to ports named CartDesiPos, or any other names. The filter component is now decoupled from the actual port names used to deploy it.
Part 3: HMI, two filters and a robot
This part adds a second filter between the first filter and the robot.
As with Parts 1 and 2, the libraries are loaded first.
<struct name="HMI" type="HMI"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>unfiltered_cartesianPosition_desi</value></simple> </struct> </struct>
<struct name="Filter1" type="OneAxisFilter"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>HMI</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="inputPosition" type="string"> <value>unfiltered_cartesianPosition_desi</value></simple> <simple name="outputPosition" type="string"> <value>filtered_cartesianPosition_desi</value></simple> </struct> <simple name="PropertyFile" type="string"> <value>../Filter1.cpf</value></simple> </struct>
<struct name="Filter2" type="OneAxisFilter"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>HMI</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="inputPosition" type="string"> <value>filtered_cartesianPosition_desi</value></simple> <simple name="outputPosition" type="string"> <value>double_filtered_cartesianPosition_desi</value></simple> </struct> <simple name="PropertyFile" type="string"> <value>../Filter2.cpf</value></simple> </struct>
<struct name="Robot" type="Robot"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.5</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="AutoStart" type="boolean"><value>1</value></simple> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>Filter2</value></simple> </struct> <struct name="Ports" type="PropertyBag"> <simple name="cartesianPosition_desi" type="string"> <value>double_filtered_cartesianPosition_desi</value></simple> </struct> </struct>
Run this part with
cd /path/to/ConnectionNaming/build deployer-macosx -s ../Connect-3.xml
Examine all components, and note which ports are connected, and what their values are. Note that the vehicle has two axes knocked out (x and y).
Points to note
- WARNING The deployer displays port names for ports within components, while the OCL reporting component also uses port names. Only the act of connecting ports between peers when deploying a component network, makes use of the connection naming shown above.
- Using connection naming allows us to reuse a component without resorting to renaming its ports or modifying its code in any way. This is an example of deployment-time configuration. Note that there are certainly instances where run-time configuration of port-names may be needed (eg the component has to name its ports based on the component name itself), but in our experience, deployment-time configuration is more frequent and decouples components better.
- Note that as many filters as are required could be chained together in this manner, and that none of the input, output, nor filter components need know that they are connected in such a fashion. Decoupling is your friend, and allowed the Filter component writer to simply concentrate on writing a component that did one thing well: filtered a cartesian position (yes, a trivial example, but a valid point nonetheless).
- You may notice that the deployment files do not specify peer combinations in pairs. The peers are mentioned in one direction only. We use this to decouple (yet again) a component from knowing what peers it is connected to, where possible. For example, Filter1 in both Parts 2 and 3 does not now what component is down-stream from it. It doesn't know, nor does it care, whether it is being filtered again, connected to a robot, or whatever. Again, decoupling. This can dramatically help when deploying large systems.
To build
In a shell
cd /path/to/ConnectionNaming mkdir build cd build cmake .. -DOROCOS_TARGET=macosx make
For other operating systems substitute the appopriate value for "macosx" when setting OROCOS_TARGET (e.g. "gnulinux").
Tested in Mac OS X Leopard 10.5.7.
Attachment | Size |
---|---|
HMI.hpp | 2.16 KB |
Robot.hpp | 1.99 KB |
OneAxisFilter.hpp | 2.52 KB |
HMI.cpp | 2.04 KB |
Robot.cpp | 1.94 KB |
OneAxisFilter.cpp | 2.92 KB |
Connect-1.xml | 1.96 KB |
Connect-2.xml | 2.91 KB |
Connect-3.xml | 3.85 KB |
connectionNaming.tar_.bz2 | 7.01 KB |
»
- Printer-friendly version
- Login or register to post comments