Rock

the Robot Construction Kit

ROS

The ROS transport provides two main functionalities:

  • the ability to generate ROS messages for every oroGen types that can be represented in ROS (see “Automatic ROS Message Convertions” below).
  • the ability to reuse existing ROS messages as a way to transport oroGen types. This is important to interface with a ROS system, as one should use ROS common messages (see “Reusing Existing ROS Messages” below).

Automatic ROS Message Convertion

There are two issues to consider when using the automatic ROS message convertion feature of oroGen:

  • naming: ROS messages is much more limited than oroGen in how they can be namespaced, so oroGen has to work around it.
  • limitations of the ROS types. The following types cannot be represented within ROS:
    • arrays-of-arrays and vectors-of-vectors
    • toplevel types that are not structures

Naming of ROS messages. For a_type/within_a_namespace/Type oroGen type which is imported into an oroGen project called “my_project”, a ROS message is generated which is named

orogen_my_project_msgs/ATypeWithinANamespaceType

Limitations The types that contain vectors-of-vectors or arrays-of-arrays are not exported to ROS. Moreover, ports using types that are not structures (e.g. std::vector<MyStruct>) can’t be subscribed / published at runtime (i.e. oroGen does not generate a corresponding boxed type).

Reusing Existing ROS Messages

Existing ROS messages can be reused by specifying ros mappings in the oroGen specification:

typekit.ros_mappings '/a_type/within_a_namespace/Type' => 'sensor_msgs/Image'

The ros_mappings statement must be added after the import_types_from statements that defined the relevant Rock type . It can only be added for types that are defined by this oroGen project. In other words, one cannot do an import_types_from “another_orogen_project” and then add a mapping for a type that is defined by another_orogen_project.

Note that once such a custom convertion is defined, it is reused by the automatic ROS message generation presented above. So, for instance, since Rock’s base/orogen/types package defines a mapping between base::Time and ros::Time, the messages generated for Rock types that contain a base::Time will use the ros Time type in their place.

In addition, you will have to provide the code that converts from the Rock type (on the left side of the mapping) and the ROS message (on the right side) yourself. The convertion code is generated by oroGen, in the typekit/ROSConvertions.hpp and typekit/ROSConvertions.cpp files. Once you have added the ros_mappings statements, run orogen once (either by launching amake or by doing a make regen in the build/ folder) to get these files. If they already existed (i.e. you are adding new mappings), the templates/typekit/ROSConvertions.* files are updated with the new convertion function signatures. Simply copy/paste the code in the typekit/ files and fill-in the functions.

Example

For instance, let’s assume that oroGen knows about a SingleRangeMeasurement type with the signature

namespace sonar_sensor
{
  struct SingleRangeMeasurement
  {
    base::Time time;
    double error;
    double distance;
  };
}

Now, let’s assume that a package called “sonar_msgs” on the ROS side already defined a message Range with the signature

time time
float64 error
float64 distance

The corresponding oroGen file would be

name 'sonar_sensor'
using_library 'sonar_sensor'
import_types_from 'base'
import_types_from "sonar_sensor/SingleRangeMeasurement.hpp"
typekit.ros_mappings '/sonar_sensor/SingleRangeMeasurement' => 'sonar_msgs/Range'

Once generated, the two convertion functions would look like:

void toROS(sonar_msgs::Range& ros,
           sonar_sensor::SingleRangeMeasurement const& value)
{
  // We have access to the ROS convertion methods for
  // other types, as e.g. here, between base::Time and ros::Time,
  // whose mapping is defined in base/orogen/types
  //
  // They are made available as we stated
  // import_types_from 'base' in the oroGen file
  toROS(ros.time, value.time);
  ros.error = value.error;
  ros.distance = value.distance;
}
void fromROS(sonar_sensor::SingleRangeMeasurement& value,
             sonar_msgs::Range const& ros)
{
  fromROS(value.time, ros.time);
  value.error = ros.error;
  value.distance = ros.distance;
}