ros2 / design

Design documentation for ROS 2.0 effort
http://design.ros2.org/
Apache License 2.0
222 stars 194 forks source link

Add type mapping info to documents #190

Closed sloretz closed 5 years ago

sloretz commented 6 years ago

This adds mappings between IDL types and other types.

dirk-thomas commented 6 years ago

1c4fa2f7e3fa92ad9145ec8e29fdeb5ad2907821 defines a custom mapping to bytes for octet arrays as well as (bounded) sequences.

deeplearningrobotics commented 6 years ago

@dirk-thomas:

As far as I understand the current concept is to generate a ROS 2 specific C++ type from an IDL. This leads to the fact that two types with the same data exist.

I have two questions:

  1. Shared Memory / Zero Copy Shared memory performance

    A DDS implementation might be able to transmit a type DDS1LaserScan with one or zero copies. But it will not understand that structure of ROS2LaserScan. So ROS2LaserScan must be converted (most likely copied) into a DDS1LaserScan1.

    How do you preserve the single / zero-copy performance?

  2. **Non ROS 2 DDS Participants***

    If a user wants to use directly DDS data writers and readers to access additional DDS features not available in ROS 2 he will be forced to use the DDS types. So an algorithm might using either using DDS1LaserScan or ROS2LaserScan.

    How do you plan integration of non-ROS 2 DDS systems without an performance impact due to type conversion?

Please also note that RTI and OpenSplice have (AFAIK) common IDL to C/C++ etc. type translations available here.

Thank you!

dirk-thomas commented 5 years ago

This leads to the fact that two types with the same data exist.

This is not a change to how the system already works. The user code always only interacts with a ROS type - it must not be coupled with a vendor specific type.

A DDS implementation might be able to transmit a type DDS1LaserScan with one or zero copies. But it will not understand that structure of ROS2LaserScan. So ROS2LaserScan must be converted (most likely copied) into a DDS1LaserScan1.

Even when using shared memory DDS implementations still need to serialize the published sample into the shared memory and on the other end deserialize it into a sample class. In the current typesupport implementations the overhead is that the ROS type is first converted to the vendor specific type which then gets serialized. Nothing should prevent a RMW implementation to skip the inbetween type and implement serialization logic from the ROS type directly.

But again: this is already the same in the current code and doesn't change in any way with the transition to using .idl file to describe the data structures.

How do you plan integration of non-ROS 2 DDS systems without an performance impact due to type conversion?

I think I don't understand the question. DDS systems define the type of exchanged sample and that is the "contract" between both endpoints. Since the data is exchanged in serialized form it is not relevant how the object representation looks like on both sides.

Please also note that RTI and OpenSplice have (AFAIK) common IDL to C/C++ etc. type translations available here.

Did you notice and differences between these translations and the ones proposed in ROS?

deeplearningrobotics commented 5 years ago

@dirk-thomas: Thank you for your reply.

Did you notice and differences between these translations and the ones proposed in ROS?

No, but I was hoping the IDL transition might enable a better interoperability between ROS 2 and native DDS application.

A lot of people ask us for all the DDS features. We want to provide that while still offering the simplicity of ROS 2. This is what makes things complicated.

In the current typesupport implementations the overhead is that the ROS type is first converted to the vendor specific type.

I was hoping for ROS 2 types having the following structure:

class ROS2PointCloud<DDSImplType> {
public:
  vector points() {
    return impl_->points();
  }
private:
  DDSImplType impl_;
};

This would allow transparent use of DDS and ROS 2 types.

I think I don't understand the question. DDS systems define the type of exchanged sample and that is the "contract" between both endpoints. Since the data is exchanged in serialized form it is not relevant how the object representation looks like on both sides.

I'll try to elaborate with an example. Assuming I write an algorithm taking in a ROS2PointCloud type.

void segmet_pc(ROS2PointCloud) {...}

Now someone wants to reuse this code in a pure DDS application. To be able to do that smoothly the output of the IDLs from ROS 2 should have the exact same API as DDS types so that I can reuse the code.

Another independent question:

dirk-thomas commented 5 years ago

No, but I was hoping the IDL transition might enable a better interoperability between ROS 2 and native DDS application.

The transition to use IDL will allow at least all the supported types to be exchanged transparently (e.g. by consensus on the encoding of strings). Other than that I don't know which exact part you would like to see "better interoperability". Maybe you can describe specific cases.

I was hoping for ROS 2 types having the following structure: class ROS2PointCloud<DDSImplType>

Making every ROS 2 data type a template based on the concrete implementation is certainly undesired. This would require compile time knowledge of the chosen RMW impl as well as increase complexity of every code using ROS messages. One of the design goals is that the ROS data types are not tied to a specific implementation and can be used even without any RMW impl. in e.g. library API. Also your example implies that all members of the data structure are only to be accessed by methods. In earlier discussions the community strongly expressed the desire to keep member-based access to all the fields.

Now someone wants to reuse this code in a pure DDS application. To be able to do that smoothly the output of the IDLs from ROS 2 should have the exact same API as DDS types so that I can reuse the code.

Not even two different DDS implementations offer the very same API for the generated data structures. So how should ROS offer that across DDS vendors (and potentially non-DDS RMW impl)? That being said most types are very close to each other (if not even identical). So nothing prevents you from implementing two signatures of the function which then use a shared function to perform the logic or use a templated function if the content of the functions works for both types.

wjwwood commented 5 years ago

I'll try to elaborate with an example. Assuming I write an algorithm taking in a ROS2PointCloud type.

void segmet_pc(ROS2PointCloud) {...}

Now someone wants to reuse this code in a pure DDS application. To be able to do that smoothly the output of the IDLs from ROS 2 should have the exact same API as DDS types so that I can reuse the code.

I'd avoid using the ROS type or the DDS type in a library unless you're willing to live with the consequences of that decision (a dependency on one or the other).

So I don't agree with the conclusion that:

In ROS 1 (and planned for ROS 2) we have something where you can pub/sub whatever type you want so long as you tell us how to serialize and deserialize it, see:

https://wiki.ros.org/roscpp/Overview/MessagesSerializationAndAdaptingTypes#Example:_Adapting_a_custom_Vector3

I think this is the right way to address the concern of wanting to use data structures different from ROS's message data structures and without incurring copying costs (for both runtime and development time).

For instance, this allows us to pub/sub PCL point clouds rather than our sensor_msgs/PointCloud2:

typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;

void callback(const PointCloud::ConstPtr& msg)
{
  printf ("Cloud: width = %d, height = %d\n", msg->width, msg->height);
  BOOST_FOREACH (const pcl::PointXYZ& pt, msg->points)
    printf ("\t(%f, %f, %f)\n", pt.x, pt.y, pt.z);
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "sub_pcl");
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe<PointCloud>("points2", 1, callback);
  ros::spin();
}

-- from: https://wiki.ros.org/pcl_ros#CA-2c92c01374035f603e08bcde0eb24382b1ccd02e_6

So, from your example, if you'd like to use DDSImplType rather than the ROS2PointCloud, you just need to tell us how to get to the DDSImplType type from the wire protocol.

dirk-thomas commented 5 years ago

@mjcarroll Please review / approve. @sloretz Please review / merge.

sloretz commented 5 years ago

LGTM, merging